From: Paladz Date: Thu, 26 Mar 2020 01:49:34 +0000 (+0800) Subject: fix fee (#523) X-Git-Tag: v1.1.0~1 X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=commitdiff_plain;h=feca8c7b2ce797e4df5131e5405706f6d5899fe2 fix fee (#523) * 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 --- diff --git a/application/mov/match/engine.go b/application/mov/match/engine.go index 4e5a0296..d332d75b 100644 --- a/application/mov/match/engine.go +++ b/application/mov/match/engine.go @@ -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 diff --git a/application/mov/match/fee_strategy.go b/application/mov/match/fee_strategy.go index 70a58a6b..1d307a0b 100644 --- a/application/mov/match/fee_strategy.go +++ b/application/mov/match/fee_strategy.go @@ -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 diff --git a/application/mov/mock/mock.go b/application/mov/mock/mock.go index 46f0bccf..0b5da6cd 100644 --- a/application/mov/mock/mock.go +++ b/application/mov/mock/mock.go @@ -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")), }, }), }