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

fix(rfq-relayer): gas estimation for zaps #3413

Merged
merged 21 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from 9 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
2 changes: 2 additions & 0 deletions services/rfq/api/model/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ type QuoteData struct {
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"`
DestAmount *string `json:"dest_amount"`
RelayerAddress *string `json:"relayer_address"`
QuoteID *string `json:"quote_id"`
Expand Down
45,054 changes: 45,054 additions & 0 deletions services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.abigen.go

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions services/rfq/contracts/bridgetransactionv2/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package bridgetransactionv2 is the bridge transaction contract.
package bridgetransactionv2

//go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../packages/contracts-rfq/flattened/BridgeTransactionV2.t.sol --pkg bridgetransactionv2 --sol-version 0.8.24 --filename bridgetransactionv2 --evm-version istanbul
35 changes: 35 additions & 0 deletions services/rfq/contracts/bridgetransactionv2/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package bridgetransactionv2

import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
)

// BridgeTransactionV2Ref is a bound fast bridge contract that returns the address of the contract.
//
//nolint:golint
type BridgeTransactionV2Ref struct {
*BridgeTransactionV2Harness
address common.Address
}

// Address gets the ocntract address.
func (f *BridgeTransactionV2Ref) Address() common.Address {
return f.address
}

// NewBridgeTransactionV2Ref creates a new fast bridge mock contract with a ref.
func NewBridgeTransactionV2Ref(address common.Address, backend bind.ContractBackend) (*BridgeTransactionV2Ref, error) {
bridgetransactionv2, err := NewBridgeTransactionV2Harness(address, backend)
if err != nil {
return nil, err
}

return &BridgeTransactionV2Ref{
BridgeTransactionV2Harness: bridgetransactionv2,
address: address,
}, nil
}

var _ vm.ContractRef = &BridgeTransactionV2Ref{}
56 changes: 56 additions & 0 deletions services/rfq/e2e/rfq_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -773,3 +773,59 @@ func (i *IntegrationSuite) TestConcurrentBridges() {
return true
})
}

// func (i *IntegrationSuite) TestEncodeBridgeTransactionParity() {
// _, handle := i.manager.GetBridgeTransactionV2(i.GetTestContext(), i.originBackend)

// originUSDC, _ := i.cctpDeployManager.GetMockMintBurnTokenType(i.GetTestContext(), i.originBackend)
// destUSDC, _ := i.cctpDeployManager.GetMockMintBurnTokenType(i.GetTestContext(), i.destBackend)
// deadline := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1))
// // zapData := []byte("Hello, world!")
// zapData := []byte{}

// bridgeTx := bridgetransactionv2.IFastBridgeV2BridgeTransactionV2{
// OriginChainId: uint32(i.originBackend.GetChainID()),
// DestChainId: uint32(i.destBackend.GetChainID()),
// OriginSender: i.userWallet.Address(),
// DestRecipient: i.userWallet.Address(),
// OriginToken: originUSDC.Address(),
// DestToken: destUSDC.Address(),
// OriginAmount: big.NewInt(1000),
// DestAmount: big.NewInt(1000),
// OriginFeeAmount: big.NewInt(10),
// Deadline: big.NewInt(0),
// Nonce: big.NewInt(0),
// ExclusivityRelayer: i.relayerWallet.Address(),
// ExclusivityEndTime: big.NewInt(0),
// ZapNative: big.NewInt(100),
// ZapData: zapData,
// }

// fmt.Printf("address: %v\n", handle.Address())
// expectedEncoded, err := handle.EncodeV2(&bind.CallOpts{Context: i.GetTestContext()}, bridgeTx)
// i.NoError(err)
// fmt.Printf("Expected: %x\n", expectedEncoded)

// tx := fastbridgev2.IFastBridgeV2BridgeTransactionV2{
// OriginChainId: uint32(i.originBackend.GetChainID()),
// DestChainId: uint32(i.destBackend.GetChainID()),
// OriginSender: i.userWallet.Address(),
// DestRecipient: i.userWallet.Address(),
// OriginToken: originUSDC.Address(),
// DestToken: destUSDC.Address(),
// OriginAmount: big.NewInt(1000),
// DestAmount: big.NewInt(1000),
// OriginFeeAmount: big.NewInt(10),
// Deadline: deadline,
// Nonce: big.NewInt(0),
// ExclusivityRelayer: common.HexToAddress(""),
// ExclusivityEndTime: big.NewInt(0),
// ZapNative: big.NewInt(100),
// ZapData: zapData,
// }

// encoded, err := chain.EncodeQuoteRequest(tx)
// i.NoError(err)

// i.Equal(expectedEncoded, encoded)
// }
83 changes: 83 additions & 0 deletions services/rfq/relayer/chain/encoding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package chain

import (
"encoding/binary"
"math/big"

"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2"
)

const (
// Field sizes in bytes

Check failure on line 11 in services/rfq/relayer/chain/encoding.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

Comment should end in a period (godot)
sizeVersion = 2
sizeChainID = 4
sizeAddress = 20
sizeUint256 = 32

// Field offsets in bytes

Check failure on line 17 in services/rfq/relayer/chain/encoding.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

Comment should end in a period (godot)
offsetVersion = 0
offsetOriginChainID = offsetVersion + sizeVersion
offsetDestChainID = offsetOriginChainID + sizeChainID
offsetOriginSender = offsetDestChainID + sizeChainID
offsetDestRecipient = offsetOriginSender + sizeAddress
offsetOriginToken = offsetDestRecipient + sizeAddress
offsetDestToken = offsetOriginToken + sizeAddress
offsetOriginAmount = offsetDestToken + sizeAddress
offsetDestAmount = offsetOriginAmount + sizeUint256
offsetOriginFeeAmount = offsetDestAmount + sizeUint256
offsetDeadline = offsetOriginFeeAmount + sizeUint256
offsetNonce = offsetDeadline + sizeUint256
offsetExclusivityRelayer = offsetNonce + sizeUint256
offsetExclusivityEndTime = offsetExclusivityRelayer + sizeAddress
offsetZapNative = offsetExclusivityEndTime + sizeUint256
offsetZapData = offsetZapNative + sizeUint256
)

// Helper function to properly encode uint256

Check failure on line 36 in services/rfq/relayer/chain/encoding.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

Comment should end in a period (godot)
func padUint256(b *big.Int) []byte {
// Convert big.Int to bytes
bytes := b.Bytes()
// Create 32-byte array (initialized to zeros)
result := make([]byte, 32)
// Copy bytes to right side of array (left-pad with zeros)
copy(result[32-len(bytes):], bytes)
return result
}

// EncodeQuoteRequest encodes a quote request into a byte array.
func EncodeQuoteRequest(tx fastbridgev2.IFastBridgeV2BridgeTransactionV2) ([]byte, error) {
result := make([]byte, offsetZapData)

// Version
result[offsetVersion] = 0
result[offsetVersion+1] = 2

// Chain IDs
binary.BigEndian.PutUint32(result[offsetOriginChainID:offsetOriginChainID+sizeChainID], tx.OriginChainId)
binary.BigEndian.PutUint32(result[offsetDestChainID:offsetDestChainID+sizeChainID], tx.DestChainId)

// Addresses
copy(result[offsetOriginSender:offsetOriginSender+sizeAddress], tx.OriginSender.Bytes())
copy(result[offsetDestRecipient:offsetDestRecipient+sizeAddress], tx.DestRecipient.Bytes())
copy(result[offsetOriginToken:offsetOriginToken+sizeAddress], tx.OriginToken.Bytes())
copy(result[offsetDestToken:offsetDestToken+sizeAddress], tx.DestToken.Bytes())

// uint256 values
copy(result[offsetOriginAmount:offsetOriginAmount+sizeUint256], padUint256(tx.OriginAmount))
copy(result[offsetDestAmount:offsetDestAmount+sizeUint256], padUint256(tx.DestAmount))
copy(result[offsetOriginFeeAmount:offsetOriginFeeAmount+sizeUint256], padUint256(tx.OriginFeeAmount))
copy(result[offsetDeadline:offsetDeadline+sizeUint256], padUint256(tx.Deadline))
copy(result[offsetNonce:offsetNonce+sizeUint256], padUint256(tx.Nonce))

// Exclusivity address
copy(result[offsetExclusivityRelayer:offsetExclusivityRelayer+sizeAddress], tx.ExclusivityRelayer.Bytes())

// More uint256 values
copy(result[offsetExclusivityEndTime:offsetExclusivityEndTime+sizeUint256], padUint256(tx.ExclusivityEndTime))
copy(result[offsetZapNative:offsetZapNative+sizeUint256], padUint256(tx.ZapNative))

// Append ZapData
result = append(result, tx.ZapData...)

Check failure on line 80 in services/rfq/relayer/chain/encoding.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

append to slice `result` with non-zero initialized length (makezero)

return result, nil
}
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

Add security validations for critical transaction fields.

The function should validate critical transaction fields to prevent potential security issues.

Consider adding these validations:

  1. Chain ID validation
  2. Address validation (non-zero)
  3. Amount validation (non-negative)
  4. Deadline validation (future timestamp)

Example implementation:

func EncodeQuoteRequest(tx fastbridgev2.IFastBridgeV2BridgeTransactionV2) ([]byte, error) {
    if err := validateTransaction(tx); err != nil {
        return nil, fmt.Errorf("invalid transaction: %w", err)
    }
    // ... rest of the function
}

func validateTransaction(tx fastbridgev2.IFastBridgeV2BridgeTransactionV2) error {
    if tx.OriginChainId == 0 || tx.DestChainId == 0 {
        return fmt.Errorf("invalid chain IDs")
    }
    if tx.OriginAmount != nil && tx.OriginAmount.Sign() < 0 {
        return fmt.Errorf("negative origin amount")
    }
    // ... more validations
    return nil
}
🧰 Tools
🪛 golangci-lint (1.62.2)

80-80: append to slice result with non-zero initialized length

(makezero)

🪛 GitHub Check: Lint (services/rfq)

[failure] 80-80:
append to slice result with non-zero initialized length (makezero)


🛠️ Refactor suggestion

Add input validation and optimize slice operations.

The encoding logic is well-structured, but there are a few improvements that could be made:

  1. Add input validation
  2. Optimize the slice append operation
  3. Consider adding error handling for potential nil fields

Apply these changes:

 func EncodeQuoteRequest(tx fastbridgev2.IFastBridgeV2BridgeTransactionV2) ([]byte, error) {
+	if tx == nil {
+		return nil, fmt.Errorf("transaction cannot be nil")
+	}
+
+	zapDataLen := len(tx.ZapData)
-	result := make([]byte, offsetZapData)
+	result := make([]byte, offsetZapData+zapDataLen)
 
 	// Version
 	result[offsetVersion] = 0
@@ -77,7 +82,7 @@
 	copy(result[offsetZapNative:offsetZapNative+sizeUint256], padUint256(tx.ZapNative))
 
 	// Append ZapData
-	result = append(result, tx.ZapData...)
+	copy(result[offsetZapData:], tx.ZapData)
📝 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
// EncodeQuoteRequest encodes a quote request into a byte array.
func EncodeQuoteRequest(tx fastbridgev2.IFastBridgeV2BridgeTransactionV2) ([]byte, error) {
result := make([]byte, offsetZapData)
// Version
result[offsetVersion] = 0
result[offsetVersion+1] = 2
// Chain IDs
binary.BigEndian.PutUint32(result[offsetOriginChainID:offsetOriginChainID+sizeChainID], tx.OriginChainId)
binary.BigEndian.PutUint32(result[offsetDestChainID:offsetDestChainID+sizeChainID], tx.DestChainId)
// Addresses
copy(result[offsetOriginSender:offsetOriginSender+sizeAddress], tx.OriginSender.Bytes())
copy(result[offsetDestRecipient:offsetDestRecipient+sizeAddress], tx.DestRecipient.Bytes())
copy(result[offsetOriginToken:offsetOriginToken+sizeAddress], tx.OriginToken.Bytes())
copy(result[offsetDestToken:offsetDestToken+sizeAddress], tx.DestToken.Bytes())
// uint256 values
copy(result[offsetOriginAmount:offsetOriginAmount+sizeUint256], padUint256(tx.OriginAmount))
copy(result[offsetDestAmount:offsetDestAmount+sizeUint256], padUint256(tx.DestAmount))
copy(result[offsetOriginFeeAmount:offsetOriginFeeAmount+sizeUint256], padUint256(tx.OriginFeeAmount))
copy(result[offsetDeadline:offsetDeadline+sizeUint256], padUint256(tx.Deadline))
copy(result[offsetNonce:offsetNonce+sizeUint256], padUint256(tx.Nonce))
// Exclusivity address
copy(result[offsetExclusivityRelayer:offsetExclusivityRelayer+sizeAddress], tx.ExclusivityRelayer.Bytes())
// More uint256 values
copy(result[offsetExclusivityEndTime:offsetExclusivityEndTime+sizeUint256], padUint256(tx.ExclusivityEndTime))
copy(result[offsetZapNative:offsetZapNative+sizeUint256], padUint256(tx.ZapNative))
// Append ZapData
result = append(result, tx.ZapData...)
return result, nil
}
// EncodeQuoteRequest encodes a quote request into a byte array.
func EncodeQuoteRequest(tx fastbridgev2.IFastBridgeV2BridgeTransactionV2) ([]byte, error) {
if tx == nil {
return nil, fmt.Errorf("transaction cannot be nil")
}
zapDataLen := len(tx.ZapData)
result := make([]byte, offsetZapData+zapDataLen)
// Version
result[offsetVersion] = 0
result[offsetVersion+1] = 2
// Chain IDs
binary.BigEndian.PutUint32(result[offsetOriginChainID:offsetOriginChainID+sizeChainID], tx.OriginChainId)
binary.BigEndian.PutUint32(result[offsetDestChainID:offsetDestChainID+sizeChainID], tx.DestChainId)
// Addresses
copy(result[offsetOriginSender:offsetOriginSender+sizeAddress], tx.OriginSender.Bytes())
copy(result[offsetDestRecipient:offsetDestRecipient+sizeAddress], tx.DestRecipient.Bytes())
copy(result[offsetOriginToken:offsetOriginToken+sizeAddress], tx.OriginToken.Bytes())
copy(result[offsetDestToken:offsetDestToken+sizeAddress], tx.DestToken.Bytes())
// uint256 values
copy(result[offsetOriginAmount:offsetOriginAmount+sizeUint256], padUint256(tx.OriginAmount))
copy(result[offsetDestAmount:offsetDestAmount+sizeUint256], padUint256(tx.DestAmount))
copy(result[offsetOriginFeeAmount:offsetOriginFeeAmount+sizeUint256], padUint256(tx.OriginFeeAmount))
copy(result[offsetDeadline:offsetDeadline+sizeUint256], padUint256(tx.Deadline))
copy(result[offsetNonce:offsetNonce+sizeUint256], padUint256(tx.Nonce))
// Exclusivity address
copy(result[offsetExclusivityRelayer:offsetExclusivityRelayer+sizeAddress], tx.ExclusivityRelayer.Bytes())
// More uint256 values
copy(result[offsetExclusivityEndTime:offsetExclusivityEndTime+sizeUint256], padUint256(tx.ExclusivityEndTime))
copy(result[offsetZapNative:offsetZapNative+sizeUint256], padUint256(tx.ZapNative))
// Append ZapData
copy(result[offsetZapData:], tx.ZapData)
return result, nil
}
🧰 Tools
🪛 golangci-lint (1.62.2)

80-80: append to slice result with non-zero initialized length

(makezero)

🪛 GitHub Check: Lint (services/rfq)

[failure] 80-80:
append to slice result with non-zero initialized length (makezero)

12 changes: 9 additions & 3 deletions services/rfq/relayer/pricer/fee_pricer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/synapsecns/sanguine/core/metrics"
"github.com/synapsecns/sanguine/ethergo/submitter"
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2"
"github.com/synapsecns/sanguine/services/rfq/relayer/chain"
"github.com/synapsecns/sanguine/services/rfq/relayer/relconfig"
"github.com/synapsecns/sanguine/services/rfq/relayer/reldb"
"go.opentelemetry.io/otel/attribute"
Expand Down Expand Up @@ -141,7 +142,7 @@ func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination

// Calculate the static L2 fee if it won't be incorporated by directly estimating the relay() call
// in addZapFees().
if quoteRequest == nil || quoteRequest.Transaction.ZapData == nil || len(quoteRequest.Transaction.ZapData) == 0 {
if quoteRequest == nil || quoteRequest.Transaction.ZapNative == nil || quoteRequest.Transaction.ZapData == nil {
gasEstimate, err := f.config.GetDestGasEstimate(int(destination))
if err != nil {
return nil, fmt.Errorf("could not get dest gas estimate: %w", err)
Expand Down Expand Up @@ -183,7 +184,7 @@ func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination
func (f *feePricer) addZapFees(ctx context.Context, destination uint32, denomToken string, quoteRequest *reldb.QuoteRequest, fee *big.Int) (*big.Int, error) {
span := trace.SpanFromContext(ctx)

if len(quoteRequest.Transaction.ZapData) > 0 {
if quoteRequest.Transaction.ZapData != nil {
gasEstimate, err := f.getZapGasEstimate(ctx, destination, quoteRequest)
if err != nil {
return nil, err
Expand Down Expand Up @@ -232,7 +233,12 @@ func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, q
fastBridgeV2ABI = &parsedABI
}

encodedData, err := fastBridgeV2ABI.Pack(methodName, quoteRequest.RawRequest, f.relayerAddress)
rawRequest, err := chain.EncodeQuoteRequest(quoteRequest.Transaction)
if err != nil {
return 0, fmt.Errorf("could not encode quote data: %w", err)
}

encodedData, err := fastBridgeV2ABI.Pack(methodName, rawRequest, f.relayerAddress)
if err != nil {
return 0, fmt.Errorf("could not encode function call: %w", err)
}
Expand Down
56 changes: 47 additions & 9 deletions services/rfq/relayer/quoter/quoter.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,16 +381,11 @@
OriginAmountExact: originAmountExact,
}
if rfqRequest.Data.ZapNative != "" || rfqRequest.Data.ZapData != "" {
zapNative, ok := new(big.Int).SetString(rfqRequest.Data.ZapNative, 10)
if !ok {
return nil, fmt.Errorf("invalid zap native amount: %s", rfqRequest.Data.ZapNative)
}
quoteInput.QuoteRequest = &reldb.QuoteRequest{
Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{
ZapNative: zapNative,
ZapData: []byte(rfqRequest.Data.ZapData),
},
quoteRequest, err := quoteDataToQuoteRequestV2(&rfqRequest.Data)
if err != nil {
return nil, fmt.Errorf("error converting quote data to quote request: %w", err)
}
quoteInput.QuoteRequest = quoteRequest
}

rawQuote, err := m.generateQuote(ctx, quoteInput)
Expand Down Expand Up @@ -432,6 +427,49 @@
return resp, nil
}

func quoteDataToQuoteRequestV2(quoteData *model.QuoteData) (*reldb.QuoteRequest, error) {
if quoteData == nil {
return nil, errors.New("quote data is nil")
}

originAmount, ok := new(big.Int).SetString(quoteData.OriginAmountExact, 10)
if !ok {
return nil, errors.New("invalid origin amount")
}
destAmount := originAmount // assume dest amount same as origin amount for estimation purposes
originFeeAmount := big.NewInt(0)
nonce := big.NewInt(0)
exclusivityEndTime := big.NewInt(0)
zapNative, ok := new(big.Int).SetString(quoteData.ZapNative, 10)
if !ok {
return nil, errors.New("invalid zap native")
}
deadline := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1))
exclusivityRelayer := common.HexToAddress("")

quoteRequest := &reldb.QuoteRequest{
Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{
OriginChainId: uint32(quoteData.OriginChainID),

Check failure on line 452 in services/rfq/relayer/quoter/quoter.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

G115: integer overflow conversion int -> uint32 (gosec)
DestChainId: uint32(quoteData.DestChainID),

Check failure on line 453 in services/rfq/relayer/quoter/quoter.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

G115: integer overflow conversion int -> uint32 (gosec)
Comment on lines +453 to +454
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

Potential integer overflow when converting int to uint32

Casting quoteData.OriginChainID and quoteData.DestChainID from int to uint32 without validation may cause integer overflows if the values are negative or exceed the uint32 maximum. This can lead to unexpected behavior or security vulnerabilities. Validate the values before casting to ensure they are within the valid uint32 range.

Apply this diff to add validation:

+    if quoteData.OriginChainID < 0 || quoteData.OriginChainID > math.MaxUint32 {
+        return nil, fmt.Errorf("OriginChainID out of range: %d", quoteData.OriginChainID)
+    }
+    if quoteData.DestChainID < 0 || quoteData.DestChainID > math.MaxUint32 {
+        return nil, fmt.Errorf("DestChainID out of range: %d", quoteData.DestChainID)
+    }
     quoteRequest := &reldb.QuoteRequest{
         Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{
             OriginChainId:      uint32(quoteData.OriginChainID),
             DestChainId:        uint32(quoteData.DestChainID),

Alternatively, if OriginChainID and DestChainID are guaranteed to be non-negative and within uint32 limits, consider changing their types to uint32 in the QuoteData struct to prevent unnecessary casting and potential errors.

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

🧰 Tools
🪛 GitHub Check: Lint (services/rfq)

[failure] 452-452:
G115: integer overflow conversion int -> uint32 (gosec)


[failure] 453-453:
G115: integer overflow conversion int -> uint32 (gosec)

OriginSender: common.HexToAddress(quoteData.OriginSender),
DestRecipient: common.HexToAddress(quoteData.DestRecipient),
Comment on lines +455 to +456
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

Validate sender and recipient addresses.

The function should validate that the sender and recipient addresses are not zero addresses to prevent potential issues with transactions.

+	if quoteData.OriginSender == "" || common.HexToAddress(quoteData.OriginSender) == (common.Address{}) {
+		return nil, errors.New("invalid origin sender address")
+	}
+	if quoteData.DestRecipient == "" || common.HexToAddress(quoteData.DestRecipient) == (common.Address{}) {
+		return nil, errors.New("invalid destination recipient address")
+	}
📝 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
OriginSender: common.HexToAddress(quoteData.OriginSender),
DestRecipient: common.HexToAddress(quoteData.DestRecipient),
if quoteData.OriginSender == "" || common.HexToAddress(quoteData.OriginSender) == (common.Address{}) {
return nil, errors.New("invalid origin sender address")
}
if quoteData.DestRecipient == "" || common.HexToAddress(quoteData.DestRecipient) == (common.Address{}) {
return nil, errors.New("invalid destination recipient address")
}
OriginSender: common.HexToAddress(quoteData.OriginSender),
DestRecipient: common.HexToAddress(quoteData.DestRecipient),

OriginToken: common.HexToAddress(quoteData.OriginTokenAddr),
DestToken: common.HexToAddress(quoteData.DestTokenAddr),
OriginAmount: originAmount,
DestAmount: destAmount,
OriginFeeAmount: originFeeAmount,
Deadline: deadline,
Nonce: nonce,
ExclusivityRelayer: exclusivityRelayer,
ExclusivityEndTime: exclusivityEndTime,
ZapNative: zapNative,
ZapData: []byte(quoteData.ZapData),
},
}

return quoteRequest, nil
}

// GetPrice gets the price of a token.
func (m *Manager) GetPrice(parentCtx context.Context, tokenName string) (_ float64, err error) {
ctx, span := m.metricsHandler.Tracer().Start(parentCtx, "GetPrice")
Expand Down
5 changes: 5 additions & 0 deletions services/rfq/testutil/contracttype.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/ethereum/go-ethereum/common/compiler"
"github.com/synapsecns/sanguine/ethergo/backends/base"
"github.com/synapsecns/sanguine/ethergo/contracts"
"github.com/synapsecns/sanguine/services/rfq/contracts/bridgetransactionv2"
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge"
"github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai"
"github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2"
Expand Down Expand Up @@ -58,6 +59,8 @@ const (
FastBridgeMockType // FastBridgeMock
// RecipientMockType is a mock contract for testing fast bridge interactions.
RecipientMockType // RecipientMock
// BridgeTransactionV2Type is a bridge transaction contract for testing fast bridge interactions.
BridgeTransactionV2Type // BridgeTransactionV2
Comment on lines +62 to +63
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Update stringer for the new BridgeTransactionV2Type contract type

The stringer generation is not up to date with the newly added contract type. Please run:

go generate ./...

to update the stringer implementation and include the BridgeTransactionV2Type in the String() method.

🔗 Analysis chain

Verify stringer generation for the new contract type

The new contract type is properly defined and documented. Since this file uses stringer generation, ensure you run:

go generate ./...
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify if stringer has been updated for the new type
rg -A 1 "func.*String.*contractTypeImpl" | grep -q "BridgeTransactionV2"
if [ $? -eq 0 ]; then
    echo "Stringer is up to date"
else
    echo "Stringer needs to be updated"
fi

Length of output: 157

// WETH9Type is the weth 9 contract.
WETH9Type // WETH9
// USDTType is the tether type.
Expand Down Expand Up @@ -100,6 +103,8 @@ func (c contractTypeImpl) ContractInfo() *compiler.Contract {
return fastbridgemockv2.Contracts["solidity/FastBridgeMock.sol:FastBridgeMock"]
case RecipientMockType:
return recipientmock.Contracts["solidity/RecipientMock.sol:RecipientMock"]
case BridgeTransactionV2Type:
return bridgetransactionv2.Contracts["solidity/BridgeTransactionV2.t.sol:BridgeTransactionV2Lib"]
case WETH9Type:
return weth9.Contracts["/solidity/WETH9.sol:WETH9"]
case USDTType:
Expand Down
13 changes: 7 additions & 6 deletions services/rfq/testutil/contracttypeimpl_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading