Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ packages:
interfaces:
PeginQuoteRepository:
PegoutQuoteRepository:
PegConfiguration:
github.com/rsksmart/liquidity-provider-server/internal/entities/blockchain:
interfaces:
BitcoinWallet:
Expand Down
56 changes: 54 additions & 2 deletions internal/entities/quote/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"fmt"
"github.com/rsksmart/liquidity-provider-server/internal/entities"
"github.com/rsksmart/liquidity-provider-server/internal/entities/utils"
log "github.com/sirupsen/logrus"
"math/big"
)

type AcceptedQuote struct {
Expand Down Expand Up @@ -44,6 +46,56 @@ func ValidateQuoteHash(hash string) error {
}

func CalculateCallFee(amount *entities.Wei, config PegConfiguration) *entities.Wei {
// TODO implement in GBI-2528
return entities.NewWei(100000000000)
var percentage *utils.BigFloat
var fixedFee *entities.Wei
result := new(entities.Wei)

if config.GetFeePercentage() != nil {
percentage = config.GetFeePercentage()
} else {
percentage = utils.NewBigFloat64(0)
}

if amount == nil {
amount = entities.NewBigWei(big.NewInt(0))
}

if config.GetFixedFee() != nil {
fixedFee = config.GetFixedFee()
} else {
fixedFee = entities.NewBigWei(big.NewInt(0))
}

percentageFee := calculatePercentageFee(amount, percentage)
result.Add(percentageFee, fixedFee)

log.Debugf("Percentage fee: %v%% of %v = %v", percentage, amount, percentageFee)
log.Debugf("Fixed fee: %v", fixedFee)
log.Debugf("Call fee: %v + %v = %v", percentageFee, fixedFee, result)
return result
}

func calculatePercentageFee(amount *entities.Wei, percentage *utils.BigFloat) *entities.Wei {
const scale = 1000 // the scale needs to have at least as many zeros as the amount of decimals we want to support in the percentage
amountAsRat := new(big.Rat).SetInt(amount.AsBigInt())
floatPercentage, _ := percentage.Native().Float64()

percentageAsFraction := new(big.Rat).SetFrac(
big.NewInt(int64(floatPercentage*scale)), // Scale to avoid precision loss
big.NewInt(100*scale),
)
percentageFee := new(big.Rat).Mul(amountAsRat, percentageAsFraction)

remainder := new(big.Int)
result, _ := new(big.Int).QuoRem(
percentageFee.Num(),
percentageFee.Denom(),
remainder,
)

// if remainder is more than half denominator round up
if new(big.Int).Mul(remainder, big.NewInt(2)).Cmp(percentageFee.Denom()) >= 0 {
result.Add(result, big.NewInt(1))
}
return entities.NewBigWei(result)
}
99 changes: 99 additions & 0 deletions internal/entities/quote/common_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package quote_test

import (
"github.com/rsksmart/liquidity-provider-server/internal/entities"
"github.com/rsksmart/liquidity-provider-server/internal/entities/utils"
"github.com/rsksmart/liquidity-provider-server/test/mocks"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"testing"

"github.com/rsksmart/liquidity-provider-server/internal/entities/quote"
Expand Down Expand Up @@ -48,3 +53,97 @@ func TestValidateQuoteHash(t *testing.T) {
})
}
}

// nolint:funlen
func TestCalculateCallFee(t *testing.T) {
type testArgs struct {
amount *entities.Wei
feePercentage *utils.BigFloat
fixedFee *entities.Wei
result *entities.Wei
}
testCases := []testArgs{
{
amount: entities.NewWei(5000000000000000),
feePercentage: utils.NewBigFloat64(0),
fixedFee: entities.NewWei(100000000000000),
result: entities.NewWei(100000000000000),
},
{
amount: entities.NewWei(5000000000000000),
feePercentage: utils.NewBigFloat64(0.33),
fixedFee: entities.NewWei(0),
result: entities.NewWei(16500000000000),
},
{
amount: entities.NewWei(5000000000000000),
feePercentage: utils.NewBigFloat64(0),
fixedFee: entities.NewWei(0),
result: entities.NewWei(0),
},
{
amount: entities.NewWei(5000000000000000),
feePercentage: utils.NewBigFloat64(5.12),
fixedFee: entities.NewWei(123456789),
result: entities.NewWei(256000123456789),
},
{
amount: entities.NewWei(7777777777777777789),
feePercentage: utils.NewBigFloat64(77.33),
fixedFee: entities.NewWei(0),
result: entities.NewWei(6014555555555555564),
},
{
amount: entities.NewWei(7777777777777777789),
feePercentage: utils.NewBigFloat64(77.44),
fixedFee: entities.NewWei(0),
result: entities.NewWei(6023111111111111120),
},
{
amount: entities.NewWei(7777777777777777789),
feePercentage: utils.NewBigFloat64(77.41),
fixedFee: entities.NewWei(0),
result: entities.NewWei(6020777777777777786),
},
{
amount: entities.NewWei(7777777777777777789),
feePercentage: utils.NewBigFloat64(77.86),
fixedFee: entities.NewWei(0),
result: entities.NewWei(6055777777777777787),
},
{
amount: entities.NewWei(7777777777777777789),
feePercentage: utils.NewBigFloat64(77.7),
fixedFee: entities.NewWei(1110000031224),
result: entities.NewWei(6043334443333364566),
},
{
amount: entities.NewWei(7777777777777777789),
feePercentage: nil,
fixedFee: entities.NewWei(1110000031224),
result: entities.NewWei(1110000031224),
},
{
amount: entities.NewWei(7777777777777777789),
feePercentage: utils.NewBigFloat64(77.7),
fixedFee: nil,
result: entities.NewWei(6043333333333333342),
},
{
amount: nil,
feePercentage: utils.NewBigFloat64(77.7),
fixedFee: entities.NewWei(1110000031224),
result: entities.NewWei(1110000031224),
},
}
log.SetLevel(log.DebugLevel)
for _, tt := range testCases {
config := &mocks.PegConfigurationMock{}
config.EXPECT().GetFeePercentage().Return(tt.feePercentage)
config.EXPECT().GetFixedFee().Return(tt.fixedFee)

result := quote.CalculateCallFee(tt.amount, config)
assert.Equal(t, tt.result, result, "Expected %v, got %v", tt.result, result)
config.AssertExpectations(t)
}
}
2 changes: 1 addition & 1 deletion internal/entities/quote/pegin_quote.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type CreatedPeginQuote struct {

type PeginCreationData struct {
GasPrice *entities.Wei `json:"gasPrice" bson:"gas_price" validate:"required"`
FeePercentage *utils.BigFloat `json:"percentageFee" bson:"percentage_fee" validate:"required"`
FeePercentage *utils.BigFloat `json:"feePercentage" bson:"percentage_fee" validate:"required"`
FixedFee *entities.Wei `json:"fixedFee" bson:"fixed_fee" validate:"required"`
}

Expand Down
2 changes: 1 addition & 1 deletion internal/entities/quote/pegout_quote.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type CreatedPegoutQuote struct {

type PegoutCreationData struct {
FeeRate *utils.BigFloat `json:"feeRate" bson:"fee_rate" validate:"required"`
FeePercentage *utils.BigFloat `json:"percentageFee" bson:"percentage_fee" validate:"required"`
FeePercentage *utils.BigFloat `json:"feePercentage" bson:"percentage_fee" validate:"required"`
GasPrice *entities.Wei `json:"gasPrice" bson:"gas_price" validate:"required"`
FixedFee *entities.Wei `json:"fixedFee" bson:"fixed_fee" validate:"required"`
}
Expand Down
4 changes: 1 addition & 3 deletions internal/usecases/pegin/get_pegin_quote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ func TestGetQuoteUseCase_Run(t *testing.T) {
quoteMatchFunction := mock.MatchedBy(func(q quote.PeginQuote) bool {
return q.FedBtcAddress == fedAddress && q.LbcAddress == lbcAddress && q.LpRskAddress == lpRskAddress &&
q.BtcRefundAddress == blockchain.BitcoinTestnetP2PKHZeroAddress && q.RskRefundAddress == userRskAddress && q.LpBtcAddress == lpBtcAddress &&
// TODO update expected value in GBI-2528
/* q.CallFee.Cmp(config.FixedFee) == 0 && */
q.PenaltyFee.Cmp(config.PenaltyFee) == 0 && q.ContractAddress == userRskAddress &&
q.PenaltyFee.Cmp(config.PenaltyFee) == 0 && q.ContractAddress == userRskAddress && q.CallFee.Cmp(entities.NewWei(163)) == 0 &&
q.Data == hex.EncodeToString(quoteData) && q.GasLimit == uint32(gasLimit.Uint64()) && q.Value.Cmp(quoteValue) == 0 &&
q.Nonce > 0 && q.TimeForDeposit == config.TimeForDeposit && q.LpCallTime == config.CallTime && q.Confirmations == 10 &&
q.CallOnRegister == false && q.GasFee.Cmp(entities.NewWei(10000)) == 0 && q.ProductFeeAmount == 0
Expand Down
2 changes: 1 addition & 1 deletion internal/usecases/pegout/get_pegout_quote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestGetQuoteUseCase_Run(t *testing.T) {
assert.Equal(t, toAddress, result.PegoutQuote.DepositAddress)
assert.Equal(t, toAddress, result.PegoutQuote.BtcRefundAddress)
assert.Equal(t, entities.NewWei(1000000000000000000), result.PegoutQuote.Value)
// assert.Equal(t, entities.NewWei(200), result.PegoutQuote.CallFee) // TODO update expected value in GBI-2528
assert.Equal(t, entities.NewWei(15500000000000200), result.PegoutQuote.CallFee)
assert.Equal(t, uint64(20), result.PegoutQuote.PenaltyFee)
assert.Equal(t, "0x1234", result.PegoutQuote.LbcAddress)
assert.NotEmpty(t, result.PegoutQuote.Nonce)
Expand Down
Loading
Loading