Skip to content
Closed
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
3 changes: 3 additions & 0 deletions .claude/rules/fee-and-quotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ globs: csharp/**

# Fee & Quote System

## Rate Field on GetQuoteResponse
`GetQuoteResponse.rate` (proto `string`, domain `QuoteWithSolverDto.Rate` as `decimal`) is the **gross, pre-fee** exchange rate returned by `IRateProvider.GetRateAsync(route)` — matches Layerswap semantics (`SwapQuoteModel.Rate` populated from the product of per-hop `route.Rate` values in `ViewModelMapper.MapQuoteResponseAsync`, where each `route.Rate` is the raw provider rate). For `SameAssetRateProvider` this is `1m`; for `TokenPriceRateProvider` it is `srcPriceUsd / dstPriceUsd`. Purely informational — the solver's fee and receive-amount math already uses this value internally; it's just surfaced now. Mapped to proto as invariant-culture `"G"` in `SolverProtoMapper.ToGetQuoteResponse`.

## Quote Fee Calculation
`QuoteService` (in `Infrastructure/Quote/QuoteService.cs`) computes total fees for a quote:

Expand Down
1 change: 1 addition & 0 deletions csharp/src/Infrastructure/Quote/QuoteService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ await CalculateTotalFeeAsync(route, amount, rewardAmountInDestNative: rewardAmou
{
Amount = amount,
ReceiveAmount = receiveAmount,
Rate = swapRate,
TotalFee = totalFee,
TotalServiceFee = totalServiceFee,
TotalExpenseFee = totalExpenseFee,
Expand Down
2 changes: 2 additions & 0 deletions csharp/src/Shared.Models/Models/QuoteWithSolverDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public class QuoteWithSolverDto : QuoteDto

public BigInteger Amount { get; set; }

public decimal Rate { get; set; }

public BigInteger RewardAmount { get; set; }

public string Signature { get; set; } = string.Empty;
Expand Down
2 changes: 2 additions & 0 deletions csharp/src/Shared.Proto/SolverProtoMapper.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Globalization;
using Google.Protobuf.WellKnownTypes;
using Train.Solver.Shared.Models.Events;
using DomainModels = Train.Solver.Shared.Models;
Expand Down Expand Up @@ -53,6 +54,7 @@ public static class SolverProtoMapper
TotalExpenseFee = quote.TotalExpenseFee.ToString(),
TotalRewardFee = quote.TotalRewardFee.ToString(),
Amount = quote.Amount.ToString(),
Rate = quote.Rate.ToString("G", CultureInfo.InvariantCulture),
};

#endregion
Expand Down
1 change: 1 addition & 0 deletions protos/solver.proto
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ message GetQuoteResponse {
string total_expense_fee = 11; // BigInteger as string (source token units)
string total_reward_fee = 12; // BigInteger as string (source token units)
string amount = 13; // BigInteger as string (source amount — useful for reverse quotes)
string rate = 14; // Gross pre-fee exchange rate from IRateProvider (decimal): destination per 1 source token
}

message RewardInfo {
Expand Down
Loading