Skip to content
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

feat(rfq-relayer): support FastBridgeV2 with arbitrary calls [SLT-320] #3258

Open
wants to merge 93 commits into
base: master
Choose a base branch
from

Conversation

dwasse
Copy link
Collaborator

@dwasse dwasse commented Oct 9, 2024

Summary by CodeRabbit

  • New Features

    • Introduced support for the new fastbridgev2 contract across various components.
    • Added new fields in data models to accommodate additional parameters for transaction handling.
    • Enhanced fee pricing logic to incorporate new parameters related to quote requests.
    • Added new mock contracts and deployment utilities for testing.
    • Implemented new methods for handling bridge transactions and encoding/decoding processes.
    • Added functionality for managing multiple versions of fast bridge contracts concurrently.
    • Introduced logging enhancements for better monitoring and debugging.
  • Bug Fixes

    • Improved error handling and logging for various operations, especially in contract interactions.
  • Documentation

    • Updated comments and documentation to reflect changes in contract versions and functionalities.
  • Tests

    • Expanded test coverage to include scenarios for the new fastbridgev2 contract and updated fee pricing logic.
    • Updated tests to verify the handling of additional fields in quote requests.

@dwasse dwasse requested a review from trajan0x as a code owner October 9, 2024 17:13
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (1)
services/rfq/relayer/pricer/fee_pricer.go (1)

261-265: Remove debug print statements

Production code should not contain debug print statements. Consider using structured logging instead.

-fmt.Printf("\nStarting getZapGasEstimate with callMsg.From: %s, callMsg.To: %s, callMsg.Value: %s, callMsg.Data: %x\n",
-   callMsg.From.Hex(), callMsg.To.Hex(), callMsg.Value.String(), callMsg.Data)
-
-fmt.Printf("\nStarting getZapGasEstimate with callMsg.From: %s, callMsg.To: %s, callMsg.Value: %s, callMsg.Data: %s\n",
-   callMsg.From.Hex(), callMsg.To.Hex(), callMsg.Value.String(), hexutil.Encode(callMsg.Data))
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf8b443 and bff2348.

📒 Files selected for processing (2)
  • services/rfq/relayer/pricer/fee_pricer.go (11 hunks)
  • services/rfq/relayer/quoter/quoter.go (8 hunks)
🔇 Additional comments (10)
services/rfq/relayer/quoter/quoter.go (4)

24-24: LGTM!

The fastbridgev2 import is correctly added to support the FastBridgeV2 integration.


402-414: LGTM!

The destination amount adjustment logic is well-implemented with proper:

  • Error handling for invalid number parsing
  • Validation to prevent negative amounts
  • Clear adjustment of destination amount by subtracting fixed fee

446-456: Review default values and assumptions in quote conversion.

Several potential issues in the implementation:

  1. Using max uint256 for deadline might be too permissive
  2. Empty exclusivity relayer address might cause contract validation issues
  3. Assuming dest amount equals origin amount might not account for token decimals or exchange rates

683-686: LGTM!

The integration of QuoteRequest into fee calculation is properly implemented with appropriate error handling.

services/rfq/relayer/pricer/fee_pricer.go (6)

33-35: LGTM: Interface changes are backward compatible

The addition of the quoteRequest parameter to GetDestinationFee and GetTotalFee methods maintains backward compatibility while extending functionality.


55-56: ⚠️ Potential issue

Add validation for relayerAddress in constructor

The relayerAddress field is critical for transaction signing and gas estimation, but lacks validation.

Also applies to: 76-76


417-418: ⚠️ Potential issue

Handle potential precision loss in fee calculations

The current implementation discards the accuracy flag from Int() conversion and might silently ignore precision loss.

Apply this fix:

-feeScaled, _ = new(big.Float).Mul(feeDenom, new(big.Float).SetFloat64(multiplier)).Int(nil)
+feeScaled, accurate := new(big.Float).Mul(feeDenom, new(big.Float).SetFloat64(multiplier)).Int(nil)
+if !accurate {
+    return nil, fmt.Errorf("fee calculation resulted in precision loss")
+}

Likely invalid or redundant comment.


146-154: ⚠️ Potential issue

Add defensive checks for Transaction field

The code accesses quoteRequest.Transaction.ZapData without checking if Transaction is nil, which could cause a panic.

Apply this fix:

-if quoteRequest == nil || len(quoteRequest.Transaction.ZapData) == 0 {
+if quoteRequest == nil || quoteRequest.Transaction == nil || len(quoteRequest.Transaction.ZapData) == 0 {

Likely invalid or redundant comment.


218-237: ⚠️ Potential issue

Fix potential data race on fastBridgeV2ABI

The global fastBridgeV2ABI variable is accessed without synchronization, which could lead to race conditions in concurrent scenarios.

Apply this fix using sync.Once:

var (
    fastBridgeV2ABI *abi.ABI
+   fastBridgeV2ABIOnce sync.Once
)

func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, quoteRequest *reldb.QuoteRequest) (gasEstimate uint64, err error) {
-   if fastBridgeV2ABI == nil {
+   var parseErr error
+   fastBridgeV2ABIOnce.Do(func() {
        parsedABI, err := abi.JSON(strings.NewReader(fastbridgev2.IFastBridgeV2MetaData.ABI))
        if err != nil {
-           return 0, fmt.Errorf("could not parse ABI: %w", err)
+           parseErr = fmt.Errorf("could not parse ABI: %w", err)
            return
        }
        fastBridgeV2ABI = &parsedABI
+   })
+   if parseErr != nil {
+       return 0, parseErr
    }

Likely invalid or redundant comment.


254-259: Verify gas estimation with non-zero values

The gas estimation should be tested with various non-zero values to ensure accurate fee calculation.

✅ Verification successful

Gas estimation is properly tested with various non-zero values

Based on the test files, gas estimation is thoroughly tested with different scenarios and values:

  • Tests include gas estimates of 500,000 to 10,000,000 units
  • Tests cover both L1 and L2 gas estimations
  • Tests verify fee calculations with different gas prices (100e9, 500e9)
  • Tests include scenarios with native token transfers (MATIC)
  • Tests validate the complete fee calculation pipeline from gas estimation to final USD amounts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify gas estimation with different value amounts
# Test various value amounts to ensure gas estimation works correctly

# Search for existing test cases
rg -A 10 "TestGetZapGasEstimate|TestAddZapFees" 

# Search for actual usage of gas estimation in production code
ast-grep --pattern 'EstimateGas($msg)'

Length of output: 90


Script:

#!/bin/bash
# Let's try a broader search for gas estimation and test patterns
rg -i "gasestimate|estimategas" -A 5

# Also search for test files related to fee calculation
fd "fee.*_test\.go"

# Look for value/native token transfer tests
rg -i "value.*test|native.*test" -A 5

Length of output: 100358


Script:

#!/bin/bash
# Let's search for test files and implementations related to fee pricer
rg -l "fee_pricer"

# Search for gas estimation test cases
rg -A 5 "TestEstimateGas|test.*gas.*estimate"

# Look for test files in the pricer directory
fd ".*_test\.go" services/rfq/relayer/pricer/

Length of output: 66272


Script:

#!/bin/bash
# Let's look for fee pricer test files and implementation
rg -A 10 "TestFeePricer|fee_pricer.*test" services/rfq/relayer/pricer/

# Search for gas estimation related code in fee pricer
rg -A 5 "GetZapGasEstimate|EstimateGas" services/rfq/relayer/pricer/

# Look for test files in the pricer directory with specific focus on gas estimation
fd ".*_test\.go" services/rfq/relayer/pricer/ | xargs rg -A 5 "gas.*estimate|estimate.*gas"

Length of output: 5227

Comment on lines 344 to 345
//tmpdebug
fmt.Printf("\nActiveRFQMessage RawMessage: %s\n", string(msg.Content))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove temporary debug print statements.

The debug print statements should be removed before merging to production as they:

  1. Could expose sensitive information in logs
  2. Add unnecessary noise to the output
  3. Are marked with "tmpdebug" comment

Apply this diff to remove the debug statements:

-    //tmpdebug
-    fmt.Printf("\nActiveRFQMessage RawMessage: %s\n", string(msg.Content))
-    fmt.Printf("RFQ Request Data: %+v\n", rfqRequest.Data)

Also applies to: 372-373

Comment on lines +201 to +213
if quoteRequest != nil && quoteRequest.Transaction.ZapNative != nil && quoteRequest.Transaction.ZapNative.Cmp(big.NewInt(0)) > 0 && quoteRequest.Transaction.ZapNative.Sign() > 0 {
callValueFloat := new(big.Float).SetInt(quoteRequest.Transaction.ZapNative)
valueDenom, err := f.getDenomFee(ctx, destination, destination, denomToken, callValueFloat)
if err != nil {
return nil, err
}
valueScaled, err := f.getFeeWithMultiplier(ctx, destination, true, valueDenom)
if err != nil {
return nil, err
}
fee = new(big.Int).Add(fee, valueScaled)
span.SetAttributes(attribute.String("value_scaled", valueScaled.String()))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for ZapNative value

The code has redundant checks for ZapNative value. The condition can be simplified and should include validation against negative values.

-if quoteRequest != nil && quoteRequest.Transaction.ZapNative != nil && quoteRequest.Transaction.ZapNative.Cmp(big.NewInt(0)) > 0 && quoteRequest.Transaction.ZapNative.Sign() > 0 {
+if quoteRequest != nil && quoteRequest.Transaction.ZapNative != nil && quoteRequest.Transaction.ZapNative.Sign() > 0 {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if quoteRequest != nil && quoteRequest.Transaction.ZapNative != nil && quoteRequest.Transaction.ZapNative.Cmp(big.NewInt(0)) > 0 && quoteRequest.Transaction.ZapNative.Sign() > 0 {
callValueFloat := new(big.Float).SetInt(quoteRequest.Transaction.ZapNative)
valueDenom, err := f.getDenomFee(ctx, destination, destination, denomToken, callValueFloat)
if err != nil {
return nil, err
}
valueScaled, err := f.getFeeWithMultiplier(ctx, destination, true, valueDenom)
if err != nil {
return nil, err
}
fee = new(big.Int).Add(fee, valueScaled)
span.SetAttributes(attribute.String("value_scaled", valueScaled.String()))
}
if quoteRequest != nil && quoteRequest.Transaction.ZapNative != nil && quoteRequest.Transaction.ZapNative.Sign() > 0 {
callValueFloat := new(big.Float).SetInt(quoteRequest.Transaction.ZapNative)
valueDenom, err := f.getDenomFee(ctx, destination, destination, denomToken, callValueFloat)
if err != nil {
return nil, err
}
valueScaled, err := f.getFeeWithMultiplier(ctx, destination, true, valueDenom)
if err != nil {
return nil, err
}
fee = new(big.Int).Add(fee, valueScaled)
span.SetAttributes(attribute.String("value_scaled", valueScaled.String()))
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (1)
services/rfq/api/rest/rfq.go (1)

Line range hint 147-156: Update getRelayerQuoteData to include FastBridgeV2 fields

The function needs to copy the new fields (ZapData, ZapNative, OriginSender, DestRecipient) from the request to maintain data consistency.

 func getRelayerQuoteData(request *model.PutRFQRequest, resp *model.WsRFQResponse) *model.QuoteData {
     return &model.QuoteData{
         OriginChainID:     request.Data.OriginChainID,
         DestChainID:       request.Data.DestChainID,
         OriginTokenAddr:   request.Data.OriginTokenAddr,
         DestTokenAddr:     request.Data.DestTokenAddr,
         OriginAmountExact: request.Data.OriginAmountExact,
+        ZapData:           request.Data.ZapData,
+        ZapNative:        request.Data.ZapNative,
+        OriginSender:     request.Data.OriginSender,
+        DestRecipient:    request.Data.DestRecipient,
         DestAmount:        &resp.DestAmount,
         QuoteID:           &resp.QuoteID,
     }
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bff2348 and 96055a7.

📒 Files selected for processing (4)
  • services/rfq/api/model/request.go (3 hunks)
  • services/rfq/api/rest/rfq.go (2 hunks)
  • services/rfq/api/rest/ws.go (5 hunks)
  • services/rfq/relayer/quoter/quoter.go (9 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • services/rfq/api/rest/ws.go
🔇 Additional comments (6)
services/rfq/api/model/request.go (1)

62-66: ⚠️ Potential issue

Input validation needed for FastBridgeV2 fields

The new fields require proper validation to ensure data integrity and security.

Previous review already highlighted this concern. To implement the validation:

 type QuoteData struct {
     // ... existing fields ...
-    ZapData           string  `json:"zap_data"`
-    ZapNative         string  `json:"zap_native"`
-    OriginAmountExact string  `json:"origin_amount_exact"`
-    OriginSender      string  `json:"origin_sender"`
-    DestRecipient     string  `json:"dest_recipient"`
+    ZapData           string  `json:"zap_data" validate:"omitempty,hexadecimal"`
+    ZapNative         string  `json:"zap_native" validate:"omitempty,numeric"`
+    OriginAmountExact string  `json:"origin_amount_exact" validate:"required,numeric"`
+    OriginSender      string  `json:"origin_sender" validate:"required,eth_addr"`
+    DestRecipient     string  `json:"dest_recipient" validate:"required,eth_addr"`
services/rfq/relayer/quoter/quoter.go (5)

24-24: LGTM!

The fastbridgev2 import is correctly added and follows the package structure.


330-330: Remove debug print statements.

The debug print statements should be removed as they could expose sensitive information and add unnecessary noise to the logs.

Also applies to: 345-346, 373-373


437-479: Review default values in quote conversion.

The implementation uses potentially problematic default values:

  1. Using max uint256 for deadline might be too permissive
  2. Empty exclusivity relayer address might cause contract validation issues

Line range hint 684-688: LGTM!

The fee calculation is correctly updated to support FastBridgeV2 by passing the QuoteRequest parameter to GetTotalFee.


403-415: Consider handling zero destination amount edge case.

While the fixed fee adjustment logic is correct, when destAmountAdj becomes zero after subtracting the fixed fee, this might lead to unexpected behavior for users. Consider:

  1. Adding a minimum viable amount check
  2. Documenting this behavior in user-facing documentation

@@ -78,6 +85,7 @@ type SubscribeActiveRFQRequest struct {

// NewWsRFQRequest creates a new WsRFQRequest.
func NewWsRFQRequest(data QuoteData, requestID string) *WsRFQRequest {
fmt.Printf("NewWsRFQRequest with data: %+v\n", data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace fmt.Printf with structured logging

Using fmt.Printf for debugging can expose sensitive data and doesn't provide proper log levels or structured output.

-    fmt.Printf("NewWsRFQRequest with data: %+v\n", data)
+    logger.Debug("Creating new WsRFQRequest",
+        "origin_chain_id", data.OriginChainID,
+        "dest_chain_id", data.DestChainID,
+        "origin_token_addr", data.OriginTokenAddr,
+        "dest_token_addr", data.DestTokenAddr)

Committable suggestion skipped: line range outside the PR's diff.

@@ -20,6 +20,7 @@ import (
const collectionTimeout = 1 * time.Minute

func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.PutRFQRequest, requestID string) (quote *model.QuoteData) {
fmt.Printf("handleActiveRFQ with request data: %+v\n", request.Data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use structured logging consistently

Debug logging should use the application's logger with appropriate log levels and structured fields.

-    fmt.Printf("handleActiveRFQ with request data: %+v\n", request.Data)
+    logger.Debug("Handling active RFQ request",
+        "request_id", requestID,
+        "origin_chain_id", request.Data.OriginChainID,
+        "dest_chain_id", request.Data.DestChainID)

     // ... existing code ...

-    fmt.Printf("parsed websocket request: %+v\n", relayerReq.Data)
+    logger.Debug("Parsed websocket request",
+        "request_id", relayerReq.RequestID,
+        "origin_chain_id", relayerReq.Data.OriginChainID,
+        "dest_chain_id", relayerReq.Data.DestChainID)

Also applies to: 34-34

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (3)
services/rfq/relayer/pricer/fee_pricer.go (3)

223-224: Remove debug print statements

Multiple debug print statements are scattered throughout the code. These should be removed or replaced with proper logging.

-    fmt.Println("Starting getZapGasEstimate with destination:", destination, "and quoteRequest:", quoteRequest)
-    fmt.Printf("\nquoteRequest.Transaction: %+v\n", quoteRequest.Transaction)
-    fmt.Printf("\nrawRequest: %+v\n", rawRequest)
-    fmt.Printf("\nStarting getZapGasEstimate with callMsg.From: %s, callMsg.To: %s, callMsg.Value: %s, callMsg.Data: %x\n",
-        callMsg.From.Hex(), callMsg.To.Hex(), callMsg.Value.String(), callMsg.Data)
-    fmt.Printf("\nStarting getZapGasEstimate with callMsg.From: %s, callMsg.To: %s, callMsg.Value: %s, callMsg.Data: %s\n",
-        callMsg.From.Hex(), callMsg.To.Hex(), callMsg.Value.String(), hexutil.Encode(callMsg.Data))

Also applies to: 239-240, 244-245, 268-272


201-213: Simplify redundant conditions and add validation

The condition for checking ZapNative contains redundant comparisons and should be simplified.

-    if quoteRequest != nil && quoteRequest.Transaction.ZapNative != nil && quoteRequest.Transaction.ZapNative.Cmp(big.NewInt(0)) > 0 && quoteRequest.Transaction.ZapNative.Sign() > 0 {
+    if quoteRequest != nil && quoteRequest.Transaction != nil && quoteRequest.Transaction.ZapNative != nil && quoteRequest.Transaction.ZapNative.Sign() > 0 {

274-277: Add retry mechanism for gas estimation

Gas estimation can be volatile and may fail temporarily. Consider adding a retry mechanism with backoff.

+    const maxRetries = 3
+    var lastErr error
+    for i := 0; i < maxRetries; i++ {
         gasEstimate, err = client.EstimateGas(ctx, callMsg)
-        if err != nil {
-            return 0, fmt.Errorf("could not estimate gas: %w", err)
+        if err == nil {
+            return gasEstimate, nil
         }
+        lastErr = err
+        time.Sleep(time.Duration(i+1) * 100 * time.Millisecond)
+    }
+    return 0, fmt.Errorf("could not estimate gas after %d retries: %w", maxRetries, lastErr)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96055a7 and b7c4f20.

📒 Files selected for processing (1)
  • services/rfq/relayer/pricer/fee_pricer.go (11 hunks)
🔇 Additional comments (4)
services/rfq/relayer/pricer/fee_pricer.go (4)

218-237: ⚠️ Potential issue

Use sync.Once for thread-safe ABI initialization

The current implementation of fastBridgeV2ABI initialization is not thread-safe.

+var (
+    fastBridgeV2ABI     *abi.ABI
+    fastBridgeV2ABIOnce sync.Once
+)

 func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, quoteRequest *reldb.QuoteRequest) (gasEstimate uint64, err error) {
-    if fastBridgeV2ABI == nil {
+    var parseErr error
+    fastBridgeV2ABIOnce.Do(func() {
         parsedABI, err := abi.JSON(strings.NewReader(fastbridgev2.IFastBridgeV2MetaData.ABI))
         if err != nil {
-            return 0, fmt.Errorf("could not parse ABI: %w", err)
+            parseErr = fmt.Errorf("could not parse ABI: %w", err)
             return
         }
         fastBridgeV2ABI = &parsedABI
+    })
+    if parseErr != nil {
+        return 0, parseErr
     }

424-425: ⚠️ Potential issue

Handle precision loss in fee calculations

The current implementation discards the accuracy flag from Int() conversion.

-    feeScaled, _ = new(big.Float).Mul(feeDenom, new(big.Float).SetFloat64(multiplier)).Int(nil)
+    feeScaled, accurate := new(big.Float).Mul(feeDenom, new(big.Float).SetFloat64(multiplier)).Int(nil)
+    if !accurate {
+        return nil, fmt.Errorf("fee calculation resulted in precision loss")
+    }

55-56: ⚠️ Potential issue

Add validation for relayerAddress

The relayerAddress parameter should be validated to ensure it's not a zero address.

 func NewFeePricer(config relconfig.Config, clientFetcher submitter.ClientFetcher, priceFetcher CoingeckoPriceFetcher, handler metrics.Handler, relayerAddress common.Address) FeePricer {
+    if relayerAddress == (common.Address{}) {
+        panic("relayerAddress cannot be zero address")
+    }

Also applies to: 60-60, 76-76


188-199: ⚠️ Potential issue

Add error handling for nil Transaction field

The code accesses quoteRequest.Transaction.ZapData without checking if Transaction is nil, which could lead to a panic.

-    if quoteRequest != nil && len(quoteRequest.Transaction.ZapData) != 0 {
+    if quoteRequest != nil && quoteRequest.Transaction != nil && len(quoteRequest.Transaction.ZapData) != 0 {

Likely invalid or redundant comment.

Comment on lines 261 to 266
callMsg := ethereum.CallMsg{
From: f.relayerAddress,
To: &rfqAddr,
Value: quoteRequest.Transaction.ZapNative,
Data: encodedData,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add gas limit to CallMsg for more accurate estimation

The CallMsg struct should include a gas limit to prevent potential out-of-gas scenarios during estimation.

 callMsg := ethereum.CallMsg{
     From:  f.relayerAddress,
     To:    &rfqAddr,
     Value: quoteRequest.Transaction.ZapNative,
     Data:  encodedData,
+    Gas:   uint64(1000000), // Set a reasonable gas limit for estimation
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
callMsg := ethereum.CallMsg{
From: f.relayerAddress,
To: &rfqAddr,
Value: quoteRequest.Transaction.ZapNative,
Data: encodedData,
}
callMsg := ethereum.CallMsg{
From: f.relayerAddress,
To: &rfqAddr,
Value: quoteRequest.Transaction.ZapNative,
Data: encodedData,
Gas: uint64(1000000), // Set a reasonable gas limit for estimation
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (3)
services/rfq/relayer/quoter/quoter.go (3)

668-668: Add documentation for the QuoteRequest field.

Consider adding a comment explaining the purpose and usage of the QuoteRequest field, especially its relationship with FastBridgeV2 functionality.

 type QuoteInput struct {
+    // QuoteRequest contains the FastBridgeV2 quote request data including arbitrary call parameters
     QuoteRequest      *reldb.QuoteRequest
 }

Line range hint 689-693: Improve error handling in fee calculation.

Consider wrapping the error with additional context about the QuoteRequest to aid in debugging.

 fee, err := m.feePricer.GetTotalFee(ctx, uint32(input.OriginChainID), uint32(input.DestChainID), destToken, true, input.QuoteRequest)
 if err != nil {
     logger.Error("Error getting total fee", "error", err)
-    return nil, fmt.Errorf("error getting total fee: %w", err)
+    return nil, fmt.Errorf("error getting total fee for chain %d->%d token %s: %w", 
+        input.OriginChainID, input.DestChainID, destToken, err)
 }

375-375: Address TODO comment about user call data.

The TODO comment indicates incomplete implementation of user call data handling.

Would you like me to help implement the user call data integration or create a GitHub issue to track this task?

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7c4f20 and 3ba6dda.

📒 Files selected for processing (1)
  • services/rfq/relayer/quoter/quoter.go (9 hunks)
🔇 Additional comments (3)
services/rfq/relayer/quoter/quoter.go (3)

330-330: Remove debug print statements.

Debug print statements should be removed before merging to production.

Also applies to: 345-346, 373-374


24-24: LGTM: Import aligns with FastBridgeV2 support.

The addition of the fastbridgev2 import is appropriate for implementing the new bridge functionality.


437-484: Review default values and assumptions in quote conversion.

Several potential issues in the implementation:

  1. Using max uint256 for deadline might be too permissive
  2. Empty exclusivity relayer address might cause contract validation issues
  3. Assuming dest amount equals origin amount might not account for token decimals or exchange rates

Comment on lines +403 to +415
// adjust dest amount by fixed fee
destAmountBigInt, ok := new(big.Int).SetString(rawQuote.DestAmount, 10)
if !ok {
return nil, fmt.Errorf("invalid dest amount: %s", rawQuote.DestAmount)
}
fixedFeeBigInt, ok := new(big.Int).SetString(rawQuote.FixedFee, 10)
if !ok {
return nil, fmt.Errorf("invalid fixed fee: %s", rawQuote.FixedFee)
}
destAmountAdj := new(big.Int).Sub(destAmountBigInt, fixedFeeBigInt)
if destAmountAdj.Sign() < 0 {
destAmountAdj = big.NewInt(0)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for minimum viable destination amount.

The destination amount adjustment could result in a zero amount, which might not be desirable for all scenarios. Consider adding validation to ensure the amount remains above a minimum viable threshold.

 destAmountAdj := new(big.Int).Sub(destAmountBigInt, fixedFeeBigInt)
 if destAmountAdj.Sign() < 0 {
-    destAmountAdj = big.NewInt(0)
+    return nil, fmt.Errorf("adjusted destination amount would be negative: amount=%s, fee=%s",
+        destAmountBigInt.String(), fixedFeeBigInt.String())
 }
+minViableAmount := big.NewInt(1000) // Configure this based on your requirements
+if destAmountAdj.Cmp(minViableAmount) < 0 {
+    return nil, fmt.Errorf("adjusted destination amount %s below minimum viable amount %s",
+        destAmountAdj.String(), minViableAmount.String())
+}

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (1)
services/rfq/api/client/client.go (1)

Line range hint 278-291: Consider enhancing websocket message monitoring

The addition of debug logging suggests a need for better visibility into message processing. Consider these improvements:

  1. Add structured logging with correlation IDs for message tracking
  2. Implement metrics for websocket message processing (success/failure rates, latency)
  3. Add proper error context when message handling fails

Would you like assistance in implementing these monitoring enhancements?

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ba6dda and ac4c1a0.

📒 Files selected for processing (3)
  • services/rfq/api/client/client.go (2 hunks)
  • services/rfq/api/rest/rfq.go (9 hunks)
  • services/rfq/relayer/quoter/quoter.go (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • services/rfq/api/rest/rfq.go
🔇 Additional comments (8)
services/rfq/relayer/quoter/quoter.go (8)

24-24: LGTM!

The import of the FastBridgeV2 package is correctly added to support the new bridge functionality.


237-240: LGTM!

The update to pass the quote to GetTotalFee is correct and necessary for accurate fee calculation with FastBridgeV2.


345-346: Remove debug print statements.

Debug print statements should be removed before merging to production.

Also applies to: 373-374


390-396: LGTM!

The FastBridgeV2 quote handling is correctly implemented with proper error handling.


403-415: Add validation for minimum viable destination amount.

Setting negative amounts to zero could lead to unexpected behavior. Consider adding validation to ensure the amount remains above a minimum viable threshold.


437-484: Review default values and assumptions in quote conversion.

Several potential issues in the implementation:

  1. Using max uint256 for deadline might be too permissive
  2. Empty exclusivity relayer address might cause contract validation issues
  3. Assuming dest amount equals origin amount might not account for token decimals or exchange rates

668-668: LGTM!

The addition of the QuoteRequest field to QuoteInput struct is well-designed and properly supports the FastBridgeV2 functionality.


Line range hint 689-693: LGTM!

The update to pass QuoteRequest to GetTotalFee is correct and maintains proper error handling.

@@ -283,6 +284,7 @@ func (c *clientImpl) processWebsocket(ctx context.Context, conn *websocket.Conn,
return fmt.Errorf("error sending message to websocket: %w", err)
}
case msg, ok := <-readChan:
fmt.Printf("recved message from readChan: %+v\n", msg)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace fmt.Printf with structured logging

Similar to the previous comment, use the logger instance for consistent logging practices.

-fmt.Printf("recved message from readChan: %+v\n", msg)
+logger.Debugf("received message from readChan: %+v", msg)

Committable suggestion skipped: line range outside the PR's diff.

@@ -275,6 +275,7 @@
case <-ctx.Done():
return nil
case msg, ok := <-reqChan:
fmt.Printf("recved message from reqChan: %+v\n", msg)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace fmt.Printf with structured logging

The debug logging should use the existing logger instance with appropriate log levels instead of fmt.Printf. This ensures consistent logging across the codebase and better control over log levels in production.

-fmt.Printf("recved message from reqChan: %+v\n", msg)
+logger.Debugf("received message from reqChan: %+v", msg)

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
services/rfq/relayer/quoter/quoter.go (2)

297-298: Document the rationale for channel buffer size.

The buffer size of 1000 seems arbitrary. Please document why this specific size was chosen and consider if it should be configurable based on system load and memory constraints.


Line range hint 379-400: Add validation for zap data length.

While the changes handle V2 quote requests correctly, consider adding validation for the zap data length to prevent potential issues with malformed input.

 if (rfqRequest.Data.ZapNative != "0" && rfqRequest.Data.ZapNative != "") || rfqRequest.Data.ZapData != "" {
+    // Validate zap data length
+    if len(rfqRequest.Data.ZapData) > 0 && len(rfqRequest.Data.ZapData) < 2 {
+        return nil, fmt.Errorf("invalid zap data length: %d", len(rfqRequest.Data.ZapData))
+    }
     quoteRequest, err := quoteDataToQuoteRequestV2(&rfqRequest.Data)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62e17de and cd6015f.

📒 Files selected for processing (3)
  • services/rfq/api/client/client.go (7 hunks)
  • services/rfq/api/rest/ws.go (8 hunks)
  • services/rfq/relayer/quoter/quoter.go (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • services/rfq/api/rest/ws.go
  • services/rfq/api/client/client.go
🔇 Additional comments (5)
services/rfq/relayer/quoter/quoter.go (5)

313-321: LGTM! Improved websocket subscription handling.

The changes enhance the robustness of the websocket subscription handling with proper error management and channel setup.


333-333: Remove debug print statements before merging.

Multiple debug print statements have been added throughout the code. These should be removed before merging to production.

Also applies to: 338-338, 349-350, 377-378, 437-437


407-419: Consider minimum viable destination amount validation.

The current implementation sets the destination amount to 0 when it would be negative after fee deduction. This could lead to undesirable behavior.


442-489: Review default values in quote conversion.

The implementation uses potentially problematic default values:

  • Maximum uint256 for deadline
  • Empty exclusivity relayer address

238-238: LGTM! Enhanced fee calculation with V2 support.

The fee calculation changes correctly integrate the quote request parameter to support FastBridgeV2 functionality.

Also applies to: 694-694

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
services/rfq/relayer/pricer/fee_pricer.go (2)

236-264: Enhance error handling in getZapGasEstimate

The error handling could be improved by:

  1. Adding context to errors for better debugging
  2. Handling potential nil client response
 func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, quoteRequest *reldb.QuoteRequest) (gasEstimate uint64, err error) {
+    if quoteRequest == nil || quoteRequest.Transaction == nil {
+        return 0, fmt.Errorf("invalid quote request: %v", quoteRequest)
+    }
     client, err := f.clientFetcher.GetClient(ctx, big.NewInt(int64(destination)))
     if err != nil {
         return 0, fmt.Errorf("could not get client: %w", err)
     }
+    if client == nil {
+        return 0, fmt.Errorf("received nil client for destination %d", destination)
+    }

Line range hint 338-384: Improve error handling in getDenomFee

The method should handle edge cases for token prices and decimal conversions.

 func (f *feePricer) getDenomFee(ctx context.Context, gasChain, denomChain uint32, denomToken string, feeWei *big.Float) (*big.Float, error) {
+    if feeWei == nil {
+        return nil, fmt.Errorf("feeWei cannot be nil")
+    }
+    if feeWei.Sign() < 0 {
+        return nil, fmt.Errorf("negative fee not allowed: %v", feeWei)
+    }
     span := trace.SpanFromContext(ctx)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd6015f and a90924e.

📒 Files selected for processing (6)
  • services/rfq/api/client/client.go (3 hunks)
  • services/rfq/api/model/request.go (2 hunks)
  • services/rfq/api/rest/rfq.go (2 hunks)
  • services/rfq/api/rest/ws.go (5 hunks)
  • services/rfq/relayer/pricer/fee_pricer.go (11 hunks)
  • services/rfq/relayer/quoter/quoter.go (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • services/rfq/api/rest/rfq.go
  • services/rfq/api/rest/ws.go
  • services/rfq/api/model/request.go
  • services/rfq/api/client/client.go
🔇 Additional comments (13)
services/rfq/relayer/quoter/quoter.go (7)

24-24: LGTM!

The fastbridgev2 import is correctly added to support the new FastBridgeV2 functionality.


296-297: LGTM!

The channel buffer size of 1000 is appropriate for the websocket subscription to prevent blocking while processing messages.


312-320: LGTM!

The changes properly implement:

  1. Buffered channel creation
  2. Error handling with proper context
  3. Correct span management for tracing

398-410: Consider adding validation for minimum viable destination amount.

Setting destAmountAdj to 0 when it becomes negative could lead to undesirable behavior. A minimum viable amount check would be more appropriate.


432-479: Review default values and assumptions in quote conversion.

The implementation has several potential issues with default values and assumptions.


663-663: LGTM!

The QuoteRequest field is properly added to support FastBridgeV2 functionality.


684-684: LGTM!

The fee calculation is correctly updated to consider FastBridgeV2 quote request data.

services/rfq/relayer/pricer/fee_pricer.go (6)

Line range hint 59-77: Add validation for relayerAddress parameter

The relayerAddress parameter should be validated to ensure it's not a zero address, as this could cause issues with gas estimation and fee calculations.


217-234: Potential Data Race on Global Variable fastBridgeV2ABI

The variable fastBridgeV2ABI is a package-level global that's set without synchronization.


408-409: Handle potential precision loss in fee calculations

The current implementation discards the accuracy flag from Int() conversion.


251-256: Add gas limit to CallMsg for more accurate estimation

The CallMsg struct should include a gas limit to prevent potential out-of-gas scenarios during estimation.


180-215: 🛠️ Refactor suggestion

Add validation for edge cases in addZapFees

The method should handle additional edge cases:

  1. Negative fee values
  2. Overflow during fee addition
 func (f *feePricer) addZapFees(ctx context.Context, destination uint32, denomToken string, quoteRequest *reldb.QuoteRequest, fee *big.Int) (*big.Int, error) {
+    if fee == nil {
+        return nil, fmt.Errorf("fee cannot be nil")
+    }
+    if fee.Sign() < 0 {
+        return nil, fmt.Errorf("negative fee not allowed: %v", fee)
+    }
     span := trace.SpanFromContext(ctx)

Likely invalid or redundant comment.


32-34: Verify backward compatibility of interface changes

The addition of the quoteRequest parameter to both GetDestinationFee and GetTotalFee methods might break existing implementations of the FeePricer interface.

✅ Verification successful

Interface changes are safe and already implemented correctly

The search results show that:

  1. There is only one implementation of the FeePricer interface in fee_pricer.go
  2. All callers (quoter.go) are already using the updated interface with the quoteRequest parameter
  3. All tests have been updated to use the new parameter, passing nil for backward compatibility
  4. The changes maintain backward compatibility as the implementation handles nil quoteRequest gracefully
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for existing implementations of FeePricer interface
ast-grep --pattern 'type $_ struct {
  $$$
}

func ($_ $_) GetDestinationFee($$$) {
  $$$
}'

Length of output: 94


Script:

#!/bin/bash
# Let's try a different approach to find implementations
# First, let's find all files that might contain FeePricer implementations
rg -l "FeePricer" --type go

# Then, let's look for the actual interface definition and its implementations
rg -A 5 "type FeePricer interface" --type go

# Also search for GetDestinationFee implementations
rg -B 2 -A 5 "func .* GetDestinationFee" --type go

Length of output: 1979


Script:

#!/bin/bash
# Let's check for any other implementations or usages of the interface
# to ensure we have a complete picture of the impact

# Check for mock implementations
rg -l "mock.*FeePricer" --type go

# Look for interface usage in tests
rg -B 2 -A 5 "NewFeePricer|mock.FeePricer" --type go

# Check for any direct calls to these methods
rg -B 2 -A 5 "GetDestinationFee\(|GetTotalFee\(" --type go

Length of output: 26885

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
services/rfq/testutil/deployers.go (1)

193-193: Fix incorrect comment

The comment incorrectly states "deploys a mock recipient contract" when it should refer to a bridge transaction contract.

-// NewBridgeTransactionV2Deployer deploys a mock recipient contract.
+// NewBridgeTransactionV2Deployer deploys a bridge transaction contract.
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19b24c6 and 551083b.

📒 Files selected for processing (3)
  • services/rfq/testutil/contracttypeimpl_string.go (1 hunks)
  • services/rfq/testutil/deployers.go (4 hunks)
  • services/rfq/testutil/typecast.go (3 hunks)
🔇 Additional comments (12)
services/rfq/testutil/contracttypeimpl_string.go (3)

12-20: LGTM: Standard Go pattern for validating iota constants

The array index validation is correctly implemented to catch changes in constant values at compile time.


Line range hint 27-34: LGTM: Standard stringer implementation

The String() method correctly implements the stringer interface with proper bounds checking and error handling.


23-25: Verify string indices alignment

The string constants and index array need to be precisely aligned. Let's verify the alignment:

✅ Verification successful

String indices are correctly aligned with contract type names

The verification confirms that the string indices in _contractTypeImpl_index array perfectly align with the contract type names in _contractTypeImpl_name. Each substring extracted using the indices matches a valid and complete contract type name:

  • FastBridgeV1 (0-12)
  • FastBridgeV2 (12-24)
  • MockERC20 (24-33)
  • FastBridgeMock (33-47)
  • RecipientMock (47-60)
  • BridgeTransactionV2 (60-79)
  • WETH9 (79-84)
  • USDT (84-88)
  • USDC (88-92)
  • DAI (92-95)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify string indices alignment with contract type names
# Expected: Each substring between indices should match a valid contract type name

# Extract and verify each contract type name
echo "FastBridgeV1FastBridgeV2MockERC20FastBridgeMockRecipientMockBridgeTransactionV2WETH9USDTUSDCDAI" | \
awk 'BEGIN{split("0,12,24,33,47,60,79,84,88,92,95",i,",")} 
     {for(j=1;j<length(i);j++) print substr($0,i[j]+1,i[j+1]-i[j])}'

Length of output: 338

services/rfq/testutil/deployers.go (4)

17-21: LGTM: Comprehensive initialization of deploy manager

The imports and deploy manager initialization correctly include all necessary contracts and deployers.

Also applies to: 33-34


125-144: LGTM: FastBridgeV2Deployer follows established pattern

The implementation correctly mirrors the existing FastBridgeDeployer pattern while using V2 contract references.


161-164: LGTM: MockFastBridgeDeployer updated for V2

The deployment implementation correctly uses V2 mock contract references.


167-186: LGTM: RecipientMockDeployer follows established pattern

The implementation correctly follows the established deployer pattern.

services/rfq/testutil/typecast.go (5)

28-33: Function addition appears consistent with existing patterns.
The new GetFastBridgeV2 method follows the established pattern of retrieving a deployed contract with manager.GetContract. Ensure this method’s usage is covered by tests to confirm correct instantiation and functionality.


49-54: Recipient mock retrieval method.
The GetRecipientMock name and comment conform to Go conventions, and the method accurately retrieves the recipient mock contract. Looks good as is.


9-9: Confirm that older imports are no longer needed.
The newly introduced imports for bridgetransactionv2, fastbridgev2, fastbridgemockv2, and recipientmock appear correct and consistent with the PR goals. If the old fastbridge references are now obsolete, consider removing that import to avoid confusion or unintentional usage.

Also applies to: 11-11, 13-13, 15-15


56-60: BridgeTransactionV2 retrieval method.
The GetBridgeTransactionV2 function is consistent with the existing pattern for deployed contracts. Ensure thorough test coverage for new BridgeTransactionV2 functionalities to prevent regressions.

✅ Verification successful

Let me gather information about the test coverage and implementation of BridgeTransactionV2.


Let me search specifically for test implementations of BridgeTransactionV2.


BridgeTransactionV2 implementation is well-tested and follows the established pattern.
The verification shows that BridgeTransactionV2 has:

  • Integration test coverage in services/rfq/e2e/rfq_test.go with TestEncodeBridgeTransactionParity
  • Proper contract bindings and implementations in both bridgetransactionv2 and fastbridgev2 packages
  • Consistent usage pattern in the relayer service handlers
  • Follows the same contract retrieval pattern as other contracts in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for test files related to BridgeTransactionV2
fd -e go -e test.go | grep -i "bridgetransaction"

# Look for BridgeTransactionV2 test implementations
rg -l "BridgeTransactionV2" --type go

# Search for test functions related to BridgeTransactionV2
ast-grep --pattern 'func Test$_($_) {
  $$$
}'

Length of output: 1278


Script:

#!/bin/bash
# Look for test cases specifically involving BridgeTransactionV2
rg -A 5 "Test.*BridgeTransaction.*" --type go

# Check the implementation of GetBridgeTransactionV2 and related tests
rg -A 10 "GetBridgeTransactionV2" --type go

# Look for any test setup involving BridgeTransactionV2
rg -A 5 "func \(.*\) (Setup|Before|Test).*BridgeTransaction.*" --type go

Length of output: 21720


43-47: Mock FastBridge updated to V2.
Switching the mock reference to fastbridgemockv2 looks aligned with the new contract version. Verify that any references to the old mock have been removed if they are no longer needed.

✅ Verification successful

Let me generate shell scripts to verify if there are any remaining references to the old FastBridge mock.


Let me search more specifically for the old FastBridge mock version and its references.


Based on the search results, I can now generate the final response:

FastBridge mock V2 update is properly implemented.
The old FastBridge mock package (fastbridgemock) appears to be kept only for reference and metadata, while all active code is using the new V2 version (fastbridgemockv2). The codebase shows consistent usage of V2 in imports and type references, with no active dependencies on the old version.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for any references to the old FastBridge mock
rg -l "fastbridgemock\." --type go

# Search for any imports of the old FastBridge mock
rg -l 'fastbridgemock"' --type go

# Search for any type declarations or variable assignments using the old mock
ast-grep --pattern 'fastbridgemock.$_'

Length of output: 1652


Script:

#!/bin/bash
# Search for files containing FastBridgeMock (case-insensitive) to catch all variations
rg -i "fastbridgemock" -A 3 --type go

# Look for any contract deployments or type definitions related to FastBridge
ast-grep --pattern 'FastBridgeMock'

# Check for any test files that might be using the old mock
fd -e go -e test.go -x rg -l "FastBridgeMock" {}

Length of output: 75417

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
services/rfq/api/rest/server_test.go (1)

542-555: 🛠️ Refactor suggestion

Add test coverage for FastBridgeV2.

The test only uses FastBridgeV1 contracts. To ensure compatibility with the new FastBridgeV2 feature, we need test coverage for both V1 and V2 contracts.

Apply this diff to support both contract versions:

 func (c *ServerSuite) sendPutQuoteRequest(header string) (*http.Response, error) {
+    // Test both V1 and V2 contracts
+    contracts := []struct {
+        name string
+        originBridge string
+        destBridge string
+    }{
+        {
+            name: "V1",
+            originBridge: c.cfg.FastBridgeContractsV1[uint32(c.originChainID)],
+            destBridge: c.cfg.FastBridgeContractsV1[uint32(c.destChainID)],
+        },
+        {
+            name: "V2",
+            originBridge: c.cfg.FastBridgeContractsV2[uint32(c.originChainID)],
+            destBridge: c.cfg.FastBridgeContractsV2[uint32(c.destChainID)],
+        },
+    }
+
+    var responses []*http.Response
+    for _, contract := range contracts {
         putData := model.PutRelayerQuoteRequest{
             OriginChainID:           c.originChainID,
             DestChainID:             c.destChainID,
             DestTokenAddr:           "0xDestTokenAddr",
             DestAmount:              "100.0",
             MaxOriginAmount:         "200.0",
             FixedFee:                "10.0",
-            OriginFastBridgeAddress: c.cfg.FastBridgeContractsV1[uint32(c.originChainID)],
-            DestFastBridgeAddress:   c.cfg.FastBridgeContractsV1[uint32(c.destChainID)],
+            OriginFastBridgeAddress: contract.originBridge,
+            DestFastBridgeAddress:   contract.destBridge,
         }
         // ... rest of the function
+        resp, err := sendRequest(putData)
+        if err != nil {
+            return nil, fmt.Errorf("failed to send %s request: %w", contract.name, err)
+        }
+        responses = append(responses, resp)
+    }
+    // Return the last response for backward compatibility
+    return responses[len(responses)-1], nil
 }
services/rfq/api/rest/server.go (1)

103-142: 🛠️ Refactor suggestion

Consider extracting duplicate initialization logic

The initialization code for V1 and V2 contracts is nearly identical. This violates the DRY principle.

Extract the common initialization logic into a helper function:

+func initializeBridgeContracts[T roleContract](
+    ctx context.Context,
+    contracts map[string]string,
+    omniRPCClient omniClient.RPCClient,
+    newContract func(common.Address, bind.ContractBackend) (T, error),
+) (map[uint32]T, map[uint32]*ttlcache.Cache[string, bool], error) {
+    bridgeContracts := make(map[uint32]T)
+    roles := make(map[uint32]*ttlcache.Cache[string, bool])
+    
+    for chainID, contract := range contracts {
+        chainClient, err := omniRPCClient.GetChainClient(ctx, int(chainID))
+        if err != nil {
+            return nil, nil, fmt.Errorf("could not create omnirpc client: %w", err)
+        }
+        
+        bridgeContracts[chainID], err = newContract(common.HexToAddress(contract), chainClient)
+        if err != nil {
+            return nil, nil, fmt.Errorf("could not create bridge contract: %w", err)
+        }
+        
+        roles[chainID] = ttlcache.New[string, bool](
+            ttlcache.WithTTL[string, bool](cacheInterval),
+        )
+        roleCache := roles[chainID]
+        go roleCache.Start()
+        go func() {
+            <-ctx.Done()
+            roleCache.Stop()
+        }()
+    }
+    return bridgeContracts, roles, nil
+}
🧹 Nitpick comments (4)
services/rfq/api/rest/server_test.go (1)

615-616: Enhance contract validation in TestContracts.

While the test verifies the length of both V1 and V2 contracts, it should also validate the contract addresses to ensure they are properly configured.

Add these assertions:

 	c.Require().Len(contracts.ContractsV1, 2)
 	c.Require().Len(contracts.ContractsV2, 2)
+	// Validate contract addresses
+	for chainID, addr := range contracts.ContractsV1 {
+		c.Require().NotEmpty(addr, "FastBridgeV1 contract address for chain %d should not be empty", chainID)
+		c.Require().True(common.IsHexAddress(addr), "FastBridgeV1 contract address %s for chain %d should be a valid hex address", addr, chainID)
+	}
+	for chainID, addr := range contracts.ContractsV2 {
+		c.Require().NotEmpty(addr, "FastBridgeV2 contract address for chain %d should not be empty", chainID)
+		c.Require().True(common.IsHexAddress(addr), "FastBridgeV2 contract address %s for chain %d should be a valid hex address", addr, chainID)
+	}
services/rfq/relayer/quoter/quoter.go (2)

388-394: Add validation for ZapNative and ZapData.

Consider adding validation to ensure:

  1. ZapNative is not negative
  2. ZapData length is within acceptable limits

Apply this diff to add validation:

 if (rfqRequest.Data.ZapNative != "0" && rfqRequest.Data.ZapNative != "") || rfqRequest.Data.ZapData != "" {
+    // Validate ZapNative is not negative
+    if zapNative, ok := new(big.Int).SetString(rfqRequest.Data.ZapNative, 10); !ok || zapNative.Sign() < 0 {
+        return nil, errors.New("invalid or negative zap native value")
+    }
+    // Validate ZapData length
+    if len(rfqRequest.Data.ZapData) > 4096 { // adjust limit as needed
+        return nil, errors.New("zap data exceeds maximum length")
+    }
     quoteRequest, err := quoteDataToQuoteRequestV2(&rfqRequest.Data)
     if err != nil {
         return nil, fmt.Errorf("error converting quote data to quote request: %w", err)
     }
     quoteInput.QuoteRequest = quoteRequest
 }

328-328: Wrap context error for consistent error handling.

The error returned from ctx.Err() should be wrapped to maintain consistent error handling throughout the codebase.

Apply this diff:

-return ctx.Err()
+return fmt.Errorf("context cancelled: %w", ctx.Err())
🧰 Tools
🪛 golangci-lint (1.62.2)

328-328: error returned from interface method should be wrapped: sig: func (context.Context).Err() error

(wrapcheck)

🪛 GitHub Check: Lint (services/rfq)

[failure] 328-328:
error returned from interface method should be wrapped: sig: func (context.Context).Err() error (wrapcheck)

services/rfq/api/rest/server.go (1)

Line range hint 391-432: Consider adding timeout to role checking

The checkRole function makes external calls without a timeout, which could lead to hanging requests.

Add a timeout to the context:

-func (r *QuoterAPIServer) checkRole(c *gin.Context, destChainID uint32, useV1 bool, role [32]byte) (addressRecovered common.Address, err error) {
+func (r *QuoterAPIServer) checkRole(c *gin.Context, destChainID uint32, useV1 bool, role [32]byte) (addressRecovered common.Address, err error) {
+    ctx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second)
+    defer cancel()
+    
     var bridge roleContract
     // ... rest of the function ...
-    ops := &bind.CallOpts{Context: c}
+    ops := &bind.CallOpts{Context: ctx}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 551083b and d4b7d23.

📒 Files selected for processing (5)
  • services/rfq/api/rest/rfq.go (2 hunks)
  • services/rfq/api/rest/rfq_test.go (1 hunks)
  • services/rfq/api/rest/server.go (10 hunks)
  • services/rfq/api/rest/server_test.go (2 hunks)
  • services/rfq/relayer/quoter/quoter.go (9 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • services/rfq/api/rest/rfq_test.go
  • services/rfq/api/rest/rfq.go
🧰 Additional context used
🪛 golangci-lint (1.62.2)
services/rfq/relayer/quoter/quoter.go

328-328: error returned from interface method should be wrapped: sig: func (context.Context).Err() error

(wrapcheck)

🪛 GitHub Check: Lint (services/rfq)
services/rfq/relayer/quoter/quoter.go

[failure] 328-328:
error returned from interface method should be wrapped: sig: func (context.Context).Err() error (wrapcheck)

🔇 Additional comments (8)
services/rfq/relayer/quoter/quoter.go (3)

24-24: LGTM: Import and struct changes for FastBridgeV2 support.

The addition of the fastbridgev2 package import and the QuoteRequest field to QuoteInput struct are well-structured changes that support the new functionality.

Also applies to: 666-666


401-413: Add validation for minimum viable destination amount.

The destination amount adjustment could result in a zero amount, which might not be desirable for all scenarios.


435-482: Review default values and assumptions in quote conversion.

Several potential issues in the implementation:

  1. Using max uint256 for deadline might be too permissive
  2. Empty exclusivity relayer address might cause contract validation issues
  3. Assuming dest amount equals origin amount might not account for token decimals or exchange rates
services/rfq/api/rest/server.go (5)

23-23: LGTM: Required imports added

The addition of errgroup for parallel execution and fastbridgev2 for the new bridge version is appropriate.

Also applies to: 39-39


56-66: LGTM: Clean struct extension

The QuoterAPIServer struct has been cleanly extended to support both V1 and V2 versions of the FastBridge contracts and role caches.


354-389: LGTM: Well-implemented parallel role checking

The checkRoleParallel function efficiently checks roles for both V1 and V2 contracts concurrently using errgroup. The error handling and fallback logic are robust.


615-629: LGTM: Improved quote handling logic

The quote handling logic has been enhanced to support both active and passive quotes, with proper error handling and telemetry.


677-687: ⚠️ Potential issue

Add input validation for ZapNative

The isZapQuote function could panic if req or req.Data is nil.

Add proper nil checks:

 func isZapQuote(req *model.PutRFQRequest) bool {
+    if req == nil || req.Data == nil {
+        return false
+    }
+
     if req.Data.ZapData != "" {
         return true
     }
 
+    if req.Data.ZapNative == "" {
+        return false
+    }
+
     zapNative, ok := new(big.Int).SetString(req.Data.ZapNative, 10)
     if !ok {
         return false
     }
     return zapNative.Sign() != 0
 }

Likely invalid or redundant comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🔭 Outside diff range comments (1)
services/rfq/guard/service/guard.go (1)

Line range hint 319-366: Consider unifying chain indexer implementations

The V1 and V2 indexer implementations share significant code. Consider creating a generic indexer implementation:

+ func (g Guard) runChainIndexer[T any](
+     ctx context.Context,
+     chainID int,
+     chainListener listener.ContractListener,
+     newParser func(common.Address) (T, error),
+     handleEvent func(context.Context, T, int) error,
+ ) error {
+     parser, err := newParser(chainListener.Address())
+     if err != nil {
+         return fmt.Errorf("could not parse: %w", err)
+     }
+     
+     return chainListener.Listen(ctx, func(parentCtx context.Context, log types.Log) error {
+         // ... common logging and event handling logic
+     })
+ }
♻️ Duplicate comments (1)
services/rfq/guard/service/guard.go (1)

262-262: ⚠️ Potential issue

Fix potential integer overflow in block number conversion

Converting log.BlockNumber from uint64 to int64 may cause integer overflow. Consider using string representation for block numbers in logs.

- attribute.Int64("block_number", int64(log.BlockNumber)),
+ attribute.String("block_number", fmt.Sprintf("%d", log.BlockNumber)),
🧹 Nitpick comments (4)
services/rfq/e2e/rfq_test.go (1)

481-486: Consider parameterizing test values

The hardcoded values for QuoteExclusivitySeconds, ZapData, and ZapNative should be extracted into constants for better maintainability.

services/rfq/e2e/setup_test.go (2)

230-245: Consider enhancing error handling in setupRecipientMock.

The error handling could be improved by returning the error instead of using i.NoError(err), allowing better error propagation and testing flexibility.

-func (i *IntegrationSuite) setupRecipientMock() {
+func (i *IntegrationSuite) setupRecipientMock() error {
   testBackends := core.ToSlice(i.originBackend, i.destBackend)

   for _, b := range testBackends {
     backend := b
     err := retry.WithBackoff(i.GetTestContext(), func(_ context.Context) (err error) {
       handle := i.manager.Get(i.GetTestContext(), backend, testutil.RecipientMockType)
       err = i.waitForContractDeployment(i.GetTestContext(), backend, handle.Address())
       if err != nil {
         return fmt.Errorf("failed to wait for contract deployment: %w", err)
       }
       return nil
     }, retry.WithMaxTotalTime(30*time.Second))
-    i.NoError(err)
+    if err != nil {
+      return fmt.Errorf("failed to setup recipient mock for backend %d: %w", backend.GetChainID(), err)
+    }
   }
+  return nil
 }

536-554: Consider consolidating role granting logic.

The role granting logic for V1 and V2 bridges is duplicated. Consider extracting this into a helper function to improve maintainability.

+func (i *IntegrationSuite) grantGuardRole(backend backends.SimulatedTestBackend, metadata contracts.DeployedContract, contract interface {
+  GUARDROLE(*bind.CallOpts) ([32]byte, error)
+  GrantRole(*bind.TransactOpts, [32]byte, common.Address) (*types.Transaction, error)
+}) error {
+  txContext := backend.GetTxContext(i.GetTestContext(), metadata.OwnerPtr())
+  guardRole, err := contract.GUARDROLE(&bind.CallOpts{Context: i.GetTestContext()})
+  if err != nil {
+    return fmt.Errorf("failed to get guard role: %w", err)
+  }
+  tx, err := contract.GrantRole(txContext.TransactOpts, guardRole, i.guardWallet.Address())
+  if err != nil {
+    return fmt.Errorf("failed to grant guard role: %w", err)
+  }
+  backend.WaitForConfirmation(i.GetTestContext(), tx)
+  return nil
+}
services/rfq/guard/service/guard.go (1)

37-40: Consider grouping related fields using nested structs

The addition of V1 and V2 specific fields creates parallel structures. Consider organizing these fields into version-specific nested structs for better maintainability:

type Guard struct {
    cfg          guardconfig.Config
    metrics      metrics.Handler
    db           guarddb.Service
    client       omniClient.RPCClient
-   contractsV1  map[int]*fastbridge.FastBridgeRef
-   contractsV2  map[int]*fastbridgev2.FastBridgeV2Ref
-   listenersV1  map[int]listener.ContractListener
-   listenersV2  map[int]listener.ContractListener
+   v1 struct {
+       contracts map[int]*fastbridge.FastBridgeRef
+       listeners map[int]listener.ContractListener
+   }
+   v2 struct {
+       contracts map[int]*fastbridgev2.FastBridgeV2Ref
+       listeners map[int]listener.ContractListener
+   }
    txSubmitter  submitter.TransactionSubmitter
    otelRecorder iOtelRecorder
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4b7d23 and 0aaf37e.

📒 Files selected for processing (5)
  • services/rfq/contracts/fastbridgev2/parser.go (1 hunks)
  • services/rfq/e2e/rfq_test.go (10 hunks)
  • services/rfq/e2e/setup_test.go (9 hunks)
  • services/rfq/guard/service/guard.go (9 hunks)
  • services/rfq/relayer/quoter/quoter.go (10 hunks)
🔇 Additional comments (18)
services/rfq/e2e/rfq_test.go (5)

24-36: LGTM: Import changes are appropriate

The new imports support the FastBridgeV2 functionality and are correctly organized.


495-511: Fix error handling in goroutine

Error handling in goroutines using i.NoError(err) is unsafe and may cause race conditions.


172-179: LGTM: Consistent V2 interface migration

The test functions have been correctly updated to use FastBridgeV2 while maintaining the original test logic and assertions.

Also applies to: 325-334


617-710: Reduce code duplication between dispute tests

TestDisputeV2 shares significant setup code with TestDisputeV1. Consider extracting common setup into helper functions.


910-912: Fix range loop in zapData generation

The range loop uses zapDataSize directly which will cause a panic. It should iterate over indices instead.

services/rfq/relayer/quoter/quoter.go (6)

24-24: LGTM: Import for FastBridgeV2 support

The import is correctly added to support the new FastBridgeV2 functionality.


301-302: Verify the channel buffer size

The buffer size of 1000 might be excessive. Consider:

  1. Monitoring channel utilization in production to tune this value
  2. Adding a configuration option for this value
  3. Implementing backpressure mechanisms if the channel fills up

317-325: LGTM: Improved error handling and channel setup

The changes enhance reliability with:

  1. Proper error handling with metrics
  2. Correct span management
  3. Buffered channel to handle load spikes

436-483: Review default values and assumptions

Several potential issues in the implementation:

  1. Using max uint256 for deadline might be too permissive
  2. Empty exclusivity relayer address might cause contract validation issues
  3. Assuming dest amount equals origin amount might not account for token decimals or exchange rates

Run the following script to verify the impact:

#!/bin/bash
# Check for any validation requirements in the FastBridgeV2 contract
ast-grep --pattern $'contract FastBridgeV2 {
  $$$
  function validateBridgeTransaction($_, $_) {
    $$$
  }
  $$$
}'

667-667: LGTM: QuoteInput struct enhancement

The addition of QuoteRequest field properly supports the FastBridgeV2 functionality.


Line range hint 688-692: LGTM: Fee calculation enhancement

The fee calculation now properly integrates with FastBridgeV2 by utilizing the QuoteRequest parameter.

services/rfq/contracts/fastbridgev2/parser.go (5)

28-28: Fix typo in comment: 'contracat' should be 'contract'.


47-47: High cyclomatic complexity in ParseEvent method.


71-75: Rename variable 'requested' to 'relayed' in 'BridgeRelayedEvent' case for clarity.


89-93: Ensure consistent naming between event type and parsing method in 'BridgeDisputeEvent' case.


94-96: Handle unknown event types explicitly.

services/rfq/e2e/setup_test.go (2)

62-69: LGTM: Bridge configuration is properly structured.

The configuration correctly handles both FastBridgeV1 and FastBridgeV2 contracts with appropriate chain IDs and addresses.


272-309: Verify token approvals for both bridge versions.

The Approve method now handles both bridge versions correctly. However, let's verify that all token approvals are properly set.

✅ Verification successful

Let me verify the token approvals for both bridge versions with additional checks.


Based on the code analysis and verification results, I can now provide the final response:

Token approvals are correctly implemented for both bridge versions

The code properly handles token approvals for both FastBridgeV1 and FastBridgeV2:

  • Checks existing allowance before approving
  • Uses abi.MaxUint256 for unlimited approval amount
  • Implements retry mechanism with backoff for failed transactions
  • Verifies allowance after approval
  • Handles each bridge version independently
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify token approvals for both bridge versions
# Search for Approval events in the codebase to ensure consistent implementation

ast-grep --pattern 'function Approve($$$) {
  $$$
  erc20.$$$
  $$$
}'

rg -A 5 'event Approval\('

Length of output: 65638


Script:

#!/bin/bash
# Search for token approval implementations and checks in the codebase
rg -A 5 'func.*Approve' services/rfq/
rg -A 5 'allowance.*=.*0' services/rfq/

Length of output: 93746

Comment on lines +399 to 433
metadataV1, rfqContractV1 := i.manager.GetFastBridge(i.GetTestContext(), backend)
txContextV1 := backend.GetTxContext(i.GetTestContext(), metadataV1.OwnerPtr())

relayerRole, err := rfqContractV1.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()})
if err != nil {
return fmt.Errorf("failed to get relayer role: %w", err)
}
proverRole, err := rfqContractV1.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()})
if err != nil {
return fmt.Errorf("failed to get relayer role: %w", err)
}
tx, err := rfqContractV1.GrantRole(txContextV1.TransactOpts, relayerRole, i.relayerWallet.Address())
if err != nil {
return fmt.Errorf("could not grant relayer role: %w", err)
}
backend.WaitForConfirmation(i.GetTestContext(), tx)

metadataV2, rfqContractV2 := i.manager.GetFastBridgeV2(i.GetTestContext(), backend)
txContextV2 := backend.GetTxContext(i.GetTestContext(), metadataV2.OwnerPtr())

txContext := backend.GetTxContext(i.GetTestContext(), metadata.OwnerPtr())
relayerRole, err := rfqContract.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()})
tx, err = rfqContractV2.GrantRole(txContextV2.TransactOpts, proverRole, i.relayerWallet.Address())
if err != nil {
return fmt.Errorf("could not get relayer role: %w", err)
return fmt.Errorf("could not grant prover role: %w", err)
}
backend.WaitForConfirmation(i.GetTestContext(), tx)

tx, err := rfqContract.GrantRole(txContext.TransactOpts, relayerRole, i.relayerWallet.Address())
quoterRole, err := rfqContractV2.QUOTERROLE(&bind.CallOpts{Context: i.GetTestContext()})
if err != nil {
return fmt.Errorf("could not grant role: %w", err)
return fmt.Errorf("could not get quoter role: %w", err)
}
tx, err = rfqContractV2.GrantRole(txContextV2.TransactOpts, quoterRole, i.relayerWallet.Address())
if err != nil {
return fmt.Errorf("could not grant quoter role: %w", err)
}
backend.WaitForConfirmation(i.GetTestContext(), tx)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix ineffectual assignment in setupRelayer.

There's an ineffectual assignment to proverRole that needs to be fixed.

-  proverRole, err := rfqContractV1.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()})
+  proverRole, err := rfqContractV1.PROVERROLE(&bind.CallOpts{Context: i.GetTestContext()})
   if err != nil {
     return fmt.Errorf("failed to get relayer role: %w", err)
   }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +67 to +92
// setup v1
rfqAddrV1, err := cfg.GetRFQAddressV1(chainID)
if err != nil {
return nil, fmt.Errorf("could not get rfq address: %w", err)
}
if rfqAddrV1 != nil {
chainClient, err := omniClient.GetChainClient(ctx, chainID)
if err != nil {
return nil, fmt.Errorf("could not get chain client: %w", err)
}
contract, err := fastbridge.NewFastBridgeRef(common.HexToAddress(*rfqAddrV1), chainClient)
if err != nil {
return nil, fmt.Errorf("could not create fast bridge contract: %w", err)
}
startBlock, err := contract.DeployBlock(&bind.CallOpts{Context: ctx})
if err != nil {
return nil, fmt.Errorf("could not get deploy block: %w", err)
}
chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(*rfqAddrV1), uint64(startBlock.Int64()), //nolint:gosec // Acceptable conversion
metricHandler, listener.WithName("guard"))
if err != nil {
return nil, fmt.Errorf("could not get chain listener: %w", err)
}
listenersV1[chainID] = chainListener
contractsV1[chainID] = contract
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Reduce code duplication in contract initialization

The initialization logic for V1 and V2 contracts contains significant duplication. Consider extracting the common initialization logic into a helper method:

+ func (g *Guard) initializeContract[T any](
+     ctx context.Context,
+     chainID int,
+     rfqAddr string,
+     newContract func(common.Address, bind.ContractBackend) (T, error),
+     metricHandler metrics.Handler,
+     listenerName string,
+ ) (T, listener.ContractListener, error) {
+     chainClient, err := g.client.GetChainClient(ctx, chainID)
+     if err != nil {
+         return nil, nil, fmt.Errorf("could not get chain client: %w", err)
+     }
+     
+     contract, err := newContract(common.HexToAddress(rfqAddr), chainClient)
+     if err != nil {
+         return nil, nil, fmt.Errorf("could not create contract: %w", err)
+     }
+     
+     startBlock, err := contract.DeployBlock(&bind.CallOpts{Context: ctx})
+     if err != nil {
+         return nil, nil, fmt.Errorf("could not get deploy block: %w", err)
+     }
+     
+     chainListener, err := listener.NewChainListener(
+         chainClient,
+         g.db,
+         common.HexToAddress(rfqAddr),
+         uint64(startBlock.Int64()),
+         metricHandler,
+         listener.WithName(listenerName),
+     )
+     if err != nil {
+         return nil, nil, fmt.Errorf("could not get chain listener: %w", err)
+     }
+     
+     return contract, chainListener, nil
+ }

This would simplify the initialization code and make it more maintainable.

Also applies to: 94-117

Comment on lines +271 to +282
v2Event := &fastbridgev2.FastBridgeV2BridgeRequested{
TransactionId: event.TransactionId,
Sender: event.Sender,
Request: event.Request,
DestChainId: event.DestChainId,
OriginToken: event.OriginToken,
DestToken: event.DestToken,
OriginAmount: event.OriginAmount,
DestAmount: event.DestAmount,
SendChainGas: event.SendChainGas,
Raw: event.Raw,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider using a type converter utility for event conversions

Manual event conversion between V1 and V2 types is error-prone and could lead to missed fields in future updates. Consider creating a dedicated converter utility:

+ type eventConverter struct{}
+ 
+ func (c *eventConverter) bridgeRequestedV1ToV2(v1 *fastbridge.FastBridgeBridgeRequested) *fastbridgev2.FastBridgeV2BridgeRequested {
+     return &fastbridgev2.FastBridgeV2BridgeRequested{
+         TransactionId: v1.TransactionId,
+         Sender:        v1.Sender,
+         Request:       v1.Request,
+         DestChainId:   v1.DestChainId,
+         OriginToken:   v1.OriginToken,
+         DestToken:     v1.DestToken,
+         OriginAmount:  v1.OriginAmount,
+         DestAmount:    v1.DestAmount,
+         SendChainGas:  v1.SendChainGas,
+         Raw:           v1.Raw,
+     }
+ }

Also applies to: 288-293, 299-303

Comment on lines +389 to +395
func (g *Guard) isV2Address(chainID int, addr common.Address) bool {
rfqAddr, err := g.cfg.GetRFQAddressV2(chainID)
if err != nil {
return false
}
return addr == common.HexToAddress(rfqAddr)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve error handling in isV2Address

The method silently fails by returning false when there's an error. Consider either:

  1. Returning the error to the caller for proper handling
  2. Logging the error for debugging purposes
- func (g *Guard) isV2Address(chainID int, addr common.Address) bool {
+ func (g *Guard) isV2Address(chainID int, addr common.Address) (bool, error) {
    rfqAddr, err := g.cfg.GetRFQAddressV2(chainID)
    if err != nil {
-       return false
+       return false, fmt.Errorf("failed to get V2 address: %w", err)
    }
-   return addr == common.HexToAddress(rfqAddr)
+   return addr == common.HexToAddress(rfqAddr), nil
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (g *Guard) isV2Address(chainID int, addr common.Address) bool {
rfqAddr, err := g.cfg.GetRFQAddressV2(chainID)
if err != nil {
return false
}
return addr == common.HexToAddress(rfqAddr)
}
func (g *Guard) isV2Address(chainID int, addr common.Address) (bool, error) {
rfqAddr, err := g.cfg.GetRFQAddressV2(chainID)
if err != nil {
return false, fmt.Errorf("failed to get V2 address: %w", err)
}
return addr == common.HexToAddress(rfqAddr), nil
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
go Pull requests that update Go code needs-go-generate-services/rfq size/l
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants