-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(rfq-relayer): profitability check accounts for offsets #3288
Changes from all commits
02e51ec
5cf7e81
46fb354
c4467f2
4c3ee56
ffbc37c
2c43ed8
a306d61
ba2a567
d682f96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -237,16 +237,44 @@ | |||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
return false, fmt.Errorf("error getting total fee: %w", err) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
cost := new(big.Int).Add(quote.Transaction.DestAmount, fee) | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
span.AddEvent("fee", trace.WithAttributes(attribute.String("fee", fee.String()))) | ||||||||||||||||||||||||
span.AddEvent("cost", trace.WithAttributes(attribute.String("cost", cost.String()))) | ||||||||||||||||||||||||
span.AddEvent("dest_amount", trace.WithAttributes(attribute.String("dest_amount", quote.Transaction.DestAmount.String()))) | ||||||||||||||||||||||||
span.AddEvent("origin_amount", trace.WithAttributes(attribute.String("origin_amount", quote.Transaction.OriginAmount.String()))) | ||||||||||||||||||||||||
// adjust amounts for our internal offsets on origin / dest token values | ||||||||||||||||||||||||
originAmountAdj, err := m.getAmountWithOffset(ctx, quote.Transaction.OriginChainId, quote.Transaction.OriginToken, quote.Transaction.OriginAmount) | ||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
return false, fmt.Errorf("error getting origin amount with offset: %w", err) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
// assume that fee is denominated in dest token terms | ||||||||||||||||||||||||
costAdj, err := m.getAmountWithOffset(ctx, quote.Transaction.DestChainId, quote.Transaction.DestToken, cost) | ||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
return false, fmt.Errorf("error getting cost with offset: %w", err) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
Comment on lines
+248
to
+251
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure non-nil 'costAdj' to prevent potential runtime panic Similar to Apply this diff to add a nil check: costAdj, err := m.getAmountWithOffset(ctx, quote.Transaction.DestChainId, quote.Transaction.DestToken, cost)
if err != nil {
return false, fmt.Errorf("error getting cost with offset: %w", err)
}
+if costAdj == nil {
+ return false, fmt.Errorf("costAdj is nil")
+} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
span.SetAttributes( | ||||||||||||||||||||||||
attribute.String("origin_amount_adj", originAmountAdj.String()), | ||||||||||||||||||||||||
attribute.String("cost_adj", costAdj.String()), | ||||||||||||||||||||||||
attribute.String("origin_amount", quote.Transaction.OriginAmount.String()), | ||||||||||||||||||||||||
attribute.String("dest_amount", quote.Transaction.DestAmount.String()), | ||||||||||||||||||||||||
attribute.String("fee", fee.String()), | ||||||||||||||||||||||||
attribute.String("cost", cost.String()), | ||||||||||||||||||||||||
) | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// NOTE: this logic assumes that the origin and destination tokens have the same price. | ||||||||||||||||||||||||
return quote.Transaction.OriginAmount.Cmp(cost) >= 0, nil | ||||||||||||||||||||||||
return originAmountAdj.Cmp(costAdj) >= 0, nil | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
func (m *Manager) getAmountWithOffset(ctx context.Context, chainID uint32, tokenAddr common.Address, amount *big.Int) (*big.Int, error) { | ||||||||||||||||||||||||
tokenName, err := m.config.GetTokenName(chainID, tokenAddr.Hex()) | ||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
return nil, fmt.Errorf("error getting token name: %w", err) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
// apply offset directly to amount without considering origin/dest | ||||||||||||||||||||||||
quoteOffsetBps, err := m.config.GetQuoteOffsetBps(int(chainID), tokenName, true) | ||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
return nil, fmt.Errorf("error getting quote offset bps: %w", err) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
amountAdj := m.applyOffset(ctx, quoteOffsetBps, amount) | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix potential precision loss in 'applyOffset' due to casting 'offsetBps' In the Modify the func (m *Manager) applyOffset(parentCtx context.Context, offsetBps float64, target *big.Int) (result *big.Int) {
_, span := m.metricsHandler.Tracer().Start(parentCtx, "applyOffset", trace.WithAttributes(
attribute.Float64("offset_bps", offsetBps),
attribute.String("target", target.String()),
))
defer func() {
metrics.EndSpan(span)
}()
- offsetFraction := new(big.Float).Quo(new(big.Float).SetInt64(int64(offsetBps)), new(big.Float).SetInt64(10000))
- offsetFactor := new(big.Float).Sub(new(big.Float).SetInt64(1), offsetFraction)
+ offsetFraction := new(big.Float).Quo(big.NewFloat(offsetBps), big.NewFloat(10000))
+ offsetFactor := new(big.Float).Sub(big.NewFloat(1), offsetFraction)
result, _ = new(big.Float).Mul(new(big.Float).SetInt(target), offsetFactor).Int(nil)
return result
} This change preserves the fractional part of
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
return amountAdj, nil | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// SubmitAllQuotes submits all quotes to the RFQ API. | ||||||||||||||||||||||||
|
@@ -580,7 +608,7 @@ | |||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// Build the quote | ||||||||||||||||||||||||
destAmount, err := m.getDestAmount(ctx, originAmount, input.DestChainID, destToken) | ||||||||||||||||||||||||
destAmount, err := m.getDestAmount(ctx, originAmount, destToken, input) | ||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
logger.Error("Error getting dest amount", "error", err) | ||||||||||||||||||||||||
return nil, fmt.Errorf("error getting dest amount: %w", err) | ||||||||||||||||||||||||
|
@@ -679,17 +707,6 @@ | |||||||||||||||||||||||
balanceFlt := new(big.Float).SetInt(input.DestBalance) | ||||||||||||||||||||||||
quoteAmount, _ = new(big.Float).Mul(balanceFlt, new(big.Float).SetFloat64(quotePct/100)).Int(nil) | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// Apply the quoteOffset to origin token. | ||||||||||||||||||||||||
tokenName, err := m.config.GetTokenName(uint32(input.DestChainID), input.DestTokenAddr.Hex()) | ||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
return nil, fmt.Errorf("error getting token name: %w", err) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
quoteOffsetBps, err := m.config.GetQuoteOffsetBps(input.OriginChainID, tokenName, true) | ||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
return nil, fmt.Errorf("error getting quote offset bps: %w", err) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
quoteAmount = m.applyOffset(ctx, quoteOffsetBps, quoteAmount) | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// Clip the quoteAmount by the minQuoteAmount | ||||||||||||||||||||||||
minQuoteAmount := m.config.GetMinQuoteAmount(input.DestChainID, input.DestTokenAddr) | ||||||||||||||||||||||||
if quoteAmount.Cmp(minQuoteAmount) < 0 { | ||||||||||||||||||||||||
|
@@ -784,28 +801,35 @@ | |||||||||||||||||||||||
|
||||||||||||||||||||||||
var errMinGasExceedsQuoteAmount = errors.New("min gas token exceeds quote amount") | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
func (m *Manager) getDestAmount(parentCtx context.Context, originAmount *big.Int, chainID int, tokenName string) (*big.Int, error) { | ||||||||||||||||||||||||
func (m *Manager) getDestAmount(parentCtx context.Context, originAmount *big.Int, tokenName string, input QuoteInput) (*big.Int, error) { | ||||||||||||||||||||||||
ctx, span := m.metricsHandler.Tracer().Start(parentCtx, "getDestAmount", trace.WithAttributes( | ||||||||||||||||||||||||
attribute.String("quote_amount", originAmount.String()), | ||||||||||||||||||||||||
)) | ||||||||||||||||||||||||
defer func() { | ||||||||||||||||||||||||
metrics.EndSpan(span) | ||||||||||||||||||||||||
}() | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
quoteOffsetBps, err := m.config.GetQuoteOffsetBps(chainID, tokenName, false) | ||||||||||||||||||||||||
// Apply origin, destination, and quote width offsets | ||||||||||||||||||||||||
originOffsetBps, err := m.config.GetQuoteOffsetBps(input.OriginChainID, tokenName, true) | ||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
return nil, fmt.Errorf("error getting quote offset bps: %w", err) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
destOffsetBps, err := m.config.GetQuoteOffsetBps(input.DestChainID, tokenName, false) | ||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
return nil, fmt.Errorf("error getting quote offset bps: %w", err) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
quoteWidthBps, err := m.config.GetQuoteWidthBps(chainID) | ||||||||||||||||||||||||
quoteWidthBps, err := m.config.GetQuoteWidthBps(input.DestChainID) | ||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||
return nil, fmt.Errorf("error getting quote width bps: %w", err) | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
totalOffsetBps := quoteOffsetBps + quoteWidthBps | ||||||||||||||||||||||||
totalOffsetBps := originOffsetBps + destOffsetBps + quoteWidthBps | ||||||||||||||||||||||||
destAmount := m.applyOffset(ctx, totalOffsetBps, originAmount) | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
span.SetAttributes( | ||||||||||||||||||||||||
attribute.Float64("quote_offset_bps", quoteOffsetBps), | ||||||||||||||||||||||||
attribute.Float64("origin_offset_bps", originOffsetBps), | ||||||||||||||||||||||||
attribute.Float64("dest_offset_bps", destOffsetBps), | ||||||||||||||||||||||||
attribute.Float64("quote_width_bps", quoteWidthBps), | ||||||||||||||||||||||||
attribute.Float64("total_offset_bps", totalOffsetBps), | ||||||||||||||||||||||||
attribute.String("dest_amount", destAmount.String()), | ||||||||||||||||||||||||
) | ||||||||||||||||||||||||
return destAmount, nil | ||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure non-nil 'originAmountAdj' to prevent potential runtime panic
After obtaining
originAmountAdj
, it is important to check if it is notnil
before using it in comparisons to avoid a possiblenil
pointer dereference.Apply this diff to add a nil check:
📝 Committable suggestion