fix fee calculation taking offer within range

This commit is contained in:
woodser 2023-05-30 12:42:50 -04:00
parent 0251b49d61
commit b90163baa5
10 changed files with 32 additions and 15 deletions

View File

@ -512,10 +512,11 @@ public class CoreApi {
public void takeOffer(String offerId, public void takeOffer(String offerId,
String paymentAccountId, String paymentAccountId,
long amountAsLong,
Consumer<Trade> resultHandler, Consumer<Trade> resultHandler,
ErrorMessageHandler errorMessageHandler) { ErrorMessageHandler errorMessageHandler) {
Offer offer = coreOffersService.getOffer(offerId); Offer offer = coreOffersService.getOffer(offerId);
coreTradesService.takeOffer(offer, paymentAccountId, resultHandler, errorMessageHandler); coreTradesService.takeOffer(offer, paymentAccountId, amountAsLong, resultHandler, errorMessageHandler);
} }
public void confirmPaymentSent(String tradeId, public void confirmPaymentSent(String tradeId,

View File

@ -89,6 +89,7 @@ class CoreTradesService {
void takeOffer(Offer offer, void takeOffer(Offer offer,
String paymentAccountId, String paymentAccountId,
long amountAsLong,
Consumer<Trade> resultHandler, Consumer<Trade> resultHandler,
ErrorMessageHandler errorMessageHandler) { ErrorMessageHandler errorMessageHandler) {
try { try {
@ -101,18 +102,21 @@ class CoreTradesService {
var useSavingsWallet = true; var useSavingsWallet = true;
// default to offer amount
BigInteger amount = amountAsLong == 0 ? offer.getAmount() : BigInteger.valueOf(amountAsLong);
// synchronize access to take offer model // TODO (woodser): to avoid synchronizing, don't use stateful model // synchronize access to take offer model // TODO (woodser): to avoid synchronizing, don't use stateful model
BigInteger takerFee; BigInteger takerFee;
BigInteger fundsNeededForTrade; BigInteger fundsNeededForTrade;
synchronized (takeOfferModel) { synchronized (takeOfferModel) {
takeOfferModel.initModel(offer, paymentAccount, useSavingsWallet); takeOfferModel.initModel(offer, paymentAccount, amount, useSavingsWallet);
takerFee = takeOfferModel.getTakerFee(); takerFee = takeOfferModel.getTakerFee();
fundsNeededForTrade = takeOfferModel.getFundsNeededForTrade(); fundsNeededForTrade = takeOfferModel.getFundsNeededForTrade();
log.info("Initiating take {} offer, {}", offer.isBuyOffer() ? "buy" : "sell", takeOfferModel); log.info("Initiating take {} offer, {}", offer.isBuyOffer() ? "buy" : "sell", takeOfferModel);
} }
// take offer // take offer
tradeManager.onTakeOffer(offer.getAmount(), tradeManager.onTakeOffer(amount,
takerFee, takerFee,
fundsNeededForTrade, fundsNeededForTrade,
offer, offer,

View File

@ -32,6 +32,8 @@ import haveno.network.p2p.P2PService;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.math.BigInteger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class OfferAvailabilityModel implements Model { public class OfferAvailabilityModel implements Model {
@ -54,6 +56,8 @@ public class OfferAvailabilityModel implements Model {
@Getter @Getter
private String paymentAccountId; private String paymentAccountId;
@Getter @Getter
private BigInteger tradeAmount;
@Getter
private OfferUtil offerUtil; private OfferUtil offerUtil;
@Getter @Getter
@Setter @Setter
@ -76,6 +80,7 @@ public class OfferAvailabilityModel implements Model {
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
boolean isTakerApiUser, boolean isTakerApiUser,
String paymentAccountId, String paymentAccountId,
BigInteger tradeAmount,
OfferUtil offerUtil) { OfferUtil offerUtil) {
this.offer = offer; this.offer = offer;
this.pubKeyRing = pubKeyRing; this.pubKeyRing = pubKeyRing;
@ -86,6 +91,7 @@ public class OfferAvailabilityModel implements Model {
this.tradeStatisticsManager = tradeStatisticsManager; this.tradeStatisticsManager = tradeStatisticsManager;
this.isTakerApiUser = isTakerApiUser; this.isTakerApiUser = isTakerApiUser;
this.paymentAccountId = paymentAccountId; this.paymentAccountId = paymentAccountId;
this.tradeAmount = tradeAmount;
this.offerUtil = offerUtil; this.offerUtil = offerUtil;
} }

View File

@ -69,9 +69,9 @@ public class SendOfferAvailabilityRequest extends Task<OfferAvailabilityModel> {
offer.getId(), offer.getId(),
P2PService.getMyNodeAddress(), P2PService.getMyNodeAddress(),
p2PService.getKeyRing().getPubKeyRing(), p2PService.getKeyRing().getPubKeyRing(),
offer.getAmount().longValueExact(), model.getTradeAmount().longValueExact(),
price.getValue(), price.getValue(),
HavenoUtils.getTakerFee(offer.getAmount()).longValueExact(), HavenoUtils.getTakerFee(model.getTradeAmount()).longValueExact(),
user.getAccountId(), user.getAccountId(),
paymentAccountId, paymentAccountId,
paymentMethodId, paymentMethodId,

View File

@ -92,6 +92,7 @@ public class TakeOfferModel implements Model {
public void initModel(Offer offer, public void initModel(Offer offer,
PaymentAccount paymentAccount, PaymentAccount paymentAccount,
BigInteger tradeAmount,
boolean useSavingsWallet) { boolean useSavingsWallet) {
this.clearModel(); this.clearModel();
this.offer = offer; this.offer = offer;
@ -100,7 +101,7 @@ public class TakeOfferModel implements Model {
validateModelInputs(); validateModelInputs();
this.useSavingsWallet = useSavingsWallet; this.useSavingsWallet = useSavingsWallet;
this.amount = offer.getAmount().min(BigInteger.valueOf(getMaxTradeLimit())); this.amount = tradeAmount.min(BigInteger.valueOf(getMaxTradeLimit()));
this.securityDeposit = offer.getDirection() == SELL this.securityDeposit = offer.getDirection() == SELL
? offer.getBuyerSecurityDeposit() ? offer.getBuyerSecurityDeposit()
: offer.getSellerSecurityDeposit(); : offer.getSellerSecurityDeposit();

View File

@ -561,11 +561,11 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
} }
// get expected taker fee // get expected taker fee
BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(offer.getOfferPayload().getAmount())); BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(request.getTradeAmount()));
// create arbitrator trade // create arbitrator trade
trade = new ArbitratorTrade(offer, trade = new ArbitratorTrade(offer,
BigInteger.valueOf(offer.getOfferPayload().getAmount()), BigInteger.valueOf(request.getTradeAmount()),
takerFee, takerFee,
offer.getOfferPayload().getPrice(), offer.getOfferPayload().getPrice(),
xmrWalletService, xmrWalletService,
@ -630,12 +630,12 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
openOfferManager.reserveOpenOffer(openOffer); openOfferManager.reserveOpenOffer(openOffer);
// get expected taker fee // get expected taker fee
BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(offer.getOfferPayload().getAmount())); BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(request.getTradeAmount()));
Trade trade; Trade trade;
if (offer.isBuyOffer()) if (offer.isBuyOffer())
trade = new BuyerAsMakerTrade(offer, trade = new BuyerAsMakerTrade(offer,
BigInteger.valueOf(offer.getOfferPayload().getAmount()), BigInteger.valueOf(request.getTradeAmount()),
takerFee, takerFee,
offer.getOfferPayload().getPrice(), offer.getOfferPayload().getPrice(),
xmrWalletService, xmrWalletService,
@ -646,7 +646,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
request.getArbitratorNodeAddress()); request.getArbitratorNodeAddress());
else else
trade = new SellerAsMakerTrade(offer, trade = new SellerAsMakerTrade(offer,
BigInteger.valueOf(offer.getOfferPayload().getAmount()), BigInteger.valueOf(request.getTradeAmount()),
takerFee, takerFee,
offer.getOfferPayload().getPrice(), offer.getOfferPayload().getPrice(),
xmrWalletService, xmrWalletService,
@ -788,9 +788,10 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
public void checkOfferAvailability(Offer offer, public void checkOfferAvailability(Offer offer,
boolean isTakerApiUser, boolean isTakerApiUser,
String paymentAccountId, String paymentAccountId,
BigInteger tradeAmount,
ResultHandler resultHandler, ResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler) { ErrorMessageHandler errorMessageHandler) {
offer.checkOfferAvailability(getOfferAvailabilityModel(offer, isTakerApiUser, paymentAccountId), resultHandler, errorMessageHandler); offer.checkOfferAvailability(getOfferAvailabilityModel(offer, isTakerApiUser, paymentAccountId, tradeAmount), resultHandler, errorMessageHandler);
} }
// First we check if offer is still available then we create the trade with the protocol // First we check if offer is still available then we create the trade with the protocol
@ -806,7 +807,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
checkArgument(!wasOfferAlreadyUsedInTrade(offer.getId())); checkArgument(!wasOfferAlreadyUsedInTrade(offer.getId()));
OfferAvailabilityModel model = getOfferAvailabilityModel(offer, isTakerApiUser, paymentAccountId); OfferAvailabilityModel model = getOfferAvailabilityModel(offer, isTakerApiUser, paymentAccountId, amount);
offer.checkOfferAvailability(model, offer.checkOfferAvailability(model,
() -> { () -> {
if (offer.getState() == Offer.State.AVAILABLE) { if (offer.getState() == Offer.State.AVAILABLE) {
@ -886,7 +887,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
processModelServiceProvider.getKeyRing().getPubKeyRing()); processModelServiceProvider.getKeyRing().getPubKeyRing());
} }
private OfferAvailabilityModel getOfferAvailabilityModel(Offer offer, boolean isTakerApiUser, String paymentAccountId) { private OfferAvailabilityModel getOfferAvailabilityModel(Offer offer, boolean isTakerApiUser, String paymentAccountId, BigInteger tradeAmount) {
return new OfferAvailabilityModel( return new OfferAvailabilityModel(
offer, offer,
keyRing.getPubKeyRing(), keyRing.getPubKeyRing(),
@ -897,6 +898,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
tradeStatisticsManager, tradeStatisticsManager,
isTakerApiUser, isTakerApiUser,
paymentAccountId, paymentAccountId,
tradeAmount,
offerUtil); offerUtil);
} }

View File

@ -54,7 +54,7 @@ public class MakerSendInitTradeRequest extends TradeTask {
offer.getId(), offer.getId(),
processModel.getMyNodeAddress(), processModel.getMyNodeAddress(),
processModel.getPubKeyRing(), processModel.getPubKeyRing(),
offer.getAmount().longValueExact(), trade.getAmount().longValueExact(),
trade.getPrice().getValue(), trade.getPrice().getValue(),
offer.getMakerFee().longValueExact(), offer.getMakerFee().longValueExact(),
trade.getProcessModel().getAccountId(), trade.getProcessModel().getAccountId(),

View File

@ -122,6 +122,7 @@ class GrpcTradesService extends TradesImplBase {
try { try {
coreApi.takeOffer(req.getOfferId(), coreApi.takeOffer(req.getOfferId(),
req.getPaymentAccountId(), req.getPaymentAccountId(),
req.getAmount(),
trade -> { trade -> {
TradeInfo tradeInfo = toTradeInfo(trade); TradeInfo tradeInfo = toTradeInfo(trade);
var reply = TakeOfferReply.newBuilder() var reply = TakeOfferReply.newBuilder()

View File

@ -156,6 +156,7 @@ class TakeOfferDataModel extends OfferDataModel {
tradeManager.checkOfferAvailability(offer, tradeManager.checkOfferAvailability(offer,
false, false,
paymentAccount.getId(), paymentAccount.getId(),
this.amount.get(),
() -> { () -> {
}, },
errorMessage -> new Popup().warning(errorMessage).show()); errorMessage -> new Popup().warning(errorMessage).show());

View File

@ -746,6 +746,7 @@ service Trades {
message TakeOfferRequest { message TakeOfferRequest {
string offer_id = 1; string offer_id = 1;
string payment_account_id = 2; string payment_account_id = 2;
uint64 amount = 3 [jstype = JS_STRING];
} }
message TakeOfferReply { message TakeOfferReply {