diff --git a/api/payments/orchestrator/internal/service/orchestrator/helpers.go b/api/payments/orchestrator/internal/service/orchestrator/helpers.go index c2e4f40..5e11ed8 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/helpers.go +++ b/api/payments/orchestrator/internal/service/orchestrator/helpers.go @@ -145,7 +145,7 @@ func resolveTradeAmounts(intentAmount *moneyv1.Money, fxQuote *oraclev1.Quote, s } } -func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.EstimateTransferFeeResponse, fxQuote *oraclev1.Quote) (*moneyv1.Money, *moneyv1.Money) { +func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.EstimateTransferFeeResponse, fxQuote *oraclev1.Quote, mode orchestratorv1.SettlementMode) (*moneyv1.Money, *moneyv1.Money) { if pay == nil { return nil, nil } @@ -166,7 +166,7 @@ func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.Est } } - adjustDebit := func(m *moneyv1.Money) { + applyChargeToDebit := func(m *moneyv1.Money) { converted, err := ensureCurrency(m, pay.GetCurrency(), fxQuote) if err != nil || converted == nil { return @@ -176,7 +176,7 @@ func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.Est } } - adjustSettlement := func(m *moneyv1.Money) { + applyChargeToSettlement := func(m *moneyv1.Money) { converted, err := ensureCurrency(m, settlementCurrency, fxQuote) if err != nil || converted == nil { return @@ -186,12 +186,22 @@ func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.Est } } - adjustDebit(fee) - adjustSettlement(fee) + switch mode { + case orchestratorv1.SettlementMode_SETTLEMENT_MODE_FIX_RECEIVED: + // Sender pays the fee: keep settlement fixed, increase debit. + applyChargeToDebit(fee) + default: + // Recipient pays the fee (default): reduce settlement, keep debit fixed. + applyChargeToSettlement(fee) + } if network != nil && network.GetNetworkFee() != nil { - adjustDebit(network.GetNetworkFee()) - adjustSettlement(network.GetNetworkFee()) + switch mode { + case orchestratorv1.SettlementMode_SETTLEMENT_MODE_FIX_RECEIVED: + applyChargeToDebit(network.GetNetworkFee()) + default: + applyChargeToSettlement(network.GetNetworkFee()) + } } return makeMoney(pay.GetCurrency(), debitDecimal), makeMoney(settlementCurrency, settlementDecimal) diff --git a/api/payments/orchestrator/internal/service/orchestrator/helpers_test.go b/api/payments/orchestrator/internal/service/orchestrator/helpers_test.go index 8c7bbd8..768ff0a 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/helpers_test.go +++ b/api/payments/orchestrator/internal/service/orchestrator/helpers_test.go @@ -7,6 +7,7 @@ import ( moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1" + orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestrator/v1" ) func TestResolveTradeAmountsBuyBase(t *testing.T) { @@ -47,11 +48,32 @@ func TestComputeAggregatesConvertsCurrencies(t *testing.T) { }, } - debit, settlement := computeAggregates(pay, settle, fee, network, fxQuote) + debit, settlement := computeAggregates(pay, settle, fee, network, fxQuote, orchestratorv1.SettlementMode_SETTLEMENT_MODE_FIX_RECEIVED) if debit.GetCurrency() != "USD" || debit.GetAmount() != "115" { t.Fatalf("expected debit 115 USD, got %s %s", debit.GetCurrency(), debit.GetAmount()) } - if settlement.GetCurrency() != "EUR" || settlement.GetAmount() != "42.5" { - t.Fatalf("expected settlement 42.5 EUR, got %s %s", settlement.GetCurrency(), settlement.GetAmount()) + if settlement.GetCurrency() != "EUR" || settlement.GetAmount() != "50" { + t.Fatalf("expected settlement 50 EUR, got %s %s", settlement.GetCurrency(), settlement.GetAmount()) + } +} + +func TestComputeAggregatesRecipientPaysFee(t *testing.T) { + pay := &moneyv1.Money{Currency: "USDT", Amount: "100"} + settle := &moneyv1.Money{Currency: "RUB", Amount: "7932"} // 100 * 79.32 + fee := &moneyv1.Money{Currency: "USDT", Amount: "7"} // 7% of 100 + fxQuote := &oraclev1.Quote{ + Pair: &fxv1.CurrencyPair{Base: "USDT", Quote: "RUB"}, + Side: fxv1.Side_SELL_BASE_BUY_QUOTE, + Price: &moneyv1.Decimal{ + Value: "79.32", + }, + } + + debit, settlement := computeAggregates(pay, settle, fee, nil, fxQuote, orchestratorv1.SettlementMode_SETTLEMENT_MODE_FIX_SOURCE) + if debit.GetCurrency() != "USDT" || debit.GetAmount() != "100" { + t.Fatalf("expected debit 100 USDT, got %s %s", debit.GetCurrency(), debit.GetAmount()) + } + if settlement.GetCurrency() != "RUB" || settlement.GetAmount() != "7376.76" { + t.Fatalf("expected settlement 7376.76 RUB, got %s %s", settlement.GetCurrency(), settlement.GetAmount()) } } diff --git a/api/payments/orchestrator/internal/service/orchestrator/quote_engine.go b/api/payments/orchestrator/internal/service/orchestrator/quote_engine.go index def97d2..5d9a4a8 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/quote_engine.go +++ b/api/payments/orchestrator/internal/service/orchestrator/quote_engine.go @@ -65,7 +65,7 @@ func (s *Service) buildPaymentQuote(ctx context.Context, orgRef string, req *orc s.logger.Debug("network fee estimated", zap.String("org_ref", orgRef)) } - debitAmount, settlementAmount := computeAggregates(payAmount, settlementAmountBeforeFees, feeTotal, networkFee, fxQuote) + debitAmount, settlementAmount := computeAggregates(payAmount, settlementAmountBeforeFees, feeTotal, networkFee, fxQuote, intent.GetSettlementMode()) quote := &orchestratorv1.PaymentQuote{ DebitAmount: debitAmount,