/
utils.go
99 lines (87 loc) · 3.04 KB
/
utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package trade
import (
"github.com/shopspring/decimal"
"github.com/tdex-network/tdex-daemon/internal/core/domain"
"github.com/tdex-network/tdex-daemon/internal/core/ports"
)
// isValidPrice checks that the amounts of the trade are valid by
// making a preview of each counter amounts of the swap given the
// current price of the market.
// Since the price is variable in time, the predicted amounts are not compared
// against those of the swap, but rather they are used to create a range in
// which the swap amounts must be included to be considered valid.
func isValidTradePrice(
market domain.Market, balance map[string]ports.Balance,
tradeType ports.TradeType, swapRequest ports.SwapRequest,
slippage decimal.Decimal,
) bool {
feeAsset := swapRequest.GetFeeAsset()
asset, amount := swapRequest.GetAssetP(), swapRequest.GetAmountP()
preview, _ := tradePreview(
market, balance, tradeType, feeAsset, asset, amount,
)
if preview != nil {
if isPriceInRange(tradeType, market, swapRequest, preview, slippage) {
return true
}
}
asset, amount = swapRequest.GetAssetR(), swapRequest.GetAmountR()
preview, _ = tradePreview(
market, balance, tradeType, feeAsset, asset, amount,
)
if preview == nil {
return false
}
return isPriceInRange(tradeType, market, swapRequest, preview, slippage)
}
func isPriceInRange(
tradeType ports.TradeType, market domain.Market,
swapRequest ports.SwapRequest, preview ports.TradePreview,
slippage decimal.Decimal,
) bool {
feeAmount := decimal.NewFromInt(int64(swapRequest.GetFeeAmount()))
feeAsset := swapRequest.GetFeeAsset()
expectedAmount := decimal.NewFromInt(int64(swapRequest.GetAmountP()))
expectedAsset := swapRequest.GetAssetP()
if preview.GetAsset() == swapRequest.GetAssetR() {
expectedAmount = decimal.NewFromInt(int64(swapRequest.GetAmountR()))
expectedAsset = swapRequest.GetAssetR()
}
amountToCheck := decimal.NewFromInt(int64(preview.GetAmount()))
if feeAsset == expectedAsset {
feesToAdd := (tradeType.IsBuy() && feeAsset == market.BaseAsset) ||
(tradeType.IsBuy() && feeAsset == market.QuoteAsset)
if feesToAdd {
expectedAmount.Add(feeAmount)
amountToCheck.Add(feeAmount)
} else {
expectedAmount.Sub(feeAmount)
amountToCheck.Sub(feeAmount)
}
}
lowerBound := expectedAmount.Mul(decimal.NewFromInt(1).Sub(slippage))
upperBound := expectedAmount.Mul(decimal.NewFromInt(1).Add(slippage))
return amountToCheck.GreaterThanOrEqual(lowerBound) &&
amountToCheck.LessThanOrEqual(upperBound)
}
func tradePreview(
mkt domain.Market, balance map[string]ports.Balance,
tradeType ports.TradeType, feeAsset, asset string, amount uint64,
) (ports.TradePreview, error) {
var baseBalance, quoteBalance uint64
if balance != nil {
if b, ok := balance[mkt.BaseAsset]; ok {
baseBalance = b.GetConfirmedBalance()
}
if b, ok := balance[mkt.QuoteAsset]; ok {
quoteBalance = b.GetConfirmedBalance()
}
}
preview, err := mkt.Preview(
baseBalance, quoteBalance, amount, asset, feeAsset, tradeType.IsBuy(),
)
if err != nil {
return nil, err
}
return previewInfo{mkt, *preview}, nil
}