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

RFQ API: add bulk quotes endpoint #2846

Merged
merged 14 commits into from
Jul 5, 2024
14 changes: 14 additions & 0 deletions services/rfq/api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
// It provides methods for creating, retrieving and updating quotes.
type AuthenticatedClient interface {
PutQuote(ctx context.Context, q *model.PutQuoteRequest) error
PutBulkQuotes(ctx context.Context, q *model.PutBulkQuotesRequest) error
PutRelayAck(ctx context.Context, req *model.PutAckRequest) (*model.PutRelayAckResponse, error)
UnauthenticatedClient
}
Expand Down Expand Up @@ -125,6 +126,19 @@ func (c *clientImpl) PutQuote(ctx context.Context, q *model.PutQuoteRequest) err
return err
}

// PutBulkQuotes puts multiple new quotes in the RFQ quoting API.
func (c *clientImpl) PutBulkQuotes(ctx context.Context, q *model.PutBulkQuotesRequest) error {
res, err := c.rClient.R().
SetContext(ctx).
SetBody(q).
Put(rest.BulkQuotesRoute)

// TODO: Figure out if there's anything to do with the response, right now it's result: Status Code 200 OK
_ = res

return err
}
Comment on lines +129 to +140
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error handling for the response.

The function PutBulkQuotes is correctly implemented to handle multiple quotes. However, it would be beneficial to handle the response to check for errors or log relevant information.

-	// TODO: Figure out if there's anything to do with the response, right now it's result: Status Code 200 OK
-	_ = res
+	if res.IsError() {
+		return fmt.Errorf("error from server: %s", res.Status())
+	}
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
// PutBulkQuotes puts multiple new quotes in the RFQ quoting API.
func (c *clientImpl) PutBulkQuotes(ctx context.Context, q *model.PutBulkQuotesRequest) error {
res, err := c.rClient.R().
SetContext(ctx).
SetBody(q).
Put(rest.BulkQuotesRoute)
// TODO: Figure out if there's anything to do with the response, right now it's result: Status Code 200 OK
_ = res
return err
}
// PutBulkQuotes puts multiple new quotes in the RFQ quoting API.
func (c *clientImpl) PutBulkQuotes(ctx context.Context, q *model.PutBulkQuotesRequest) error {
res, err := c.rClient.R().
SetContext(ctx).
SetBody(q).
Put(rest.BulkQuotesRoute)
// TODO: Figure out if there's anything to do with the response, right now it's result: Status Code 200 OK
if res.IsError() {
return fmt.Errorf("error from server: %s", res.Status())
}
return err
}


func (c *clientImpl) PutRelayAck(ctx context.Context, req *model.PutAckRequest) (*model.PutRelayAckResponse, error) {
var ack *model.PutRelayAckResponse
resp, err := c.rClient.R().
Expand Down
59 changes: 59 additions & 0 deletions services/rfq/api/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,65 @@ func (c *ClientSuite) TestPutAndGetQuote() {
c.Equal(expectedResp, *quotes[0])
}

func (c *ClientSuite) TestPutAndGetBulkQuotes() {
req := model.PutBulkQuotesRequest{
Quotes: []model.PutQuoteRequest{
{
OriginChainID: 1,
OriginTokenAddr: "0xOriginTokenAddr",
DestChainID: 42161,
DestTokenAddr: "0xDestTokenAddr",
DestAmount: "100",
MaxOriginAmount: "200",
FixedFee: "10",
},
{
OriginChainID: 42161,
OriginTokenAddr: "0xOriginTokenAddr",
DestChainID: 1,
DestTokenAddr: "0xDestTokenAddr",
DestAmount: "100",
MaxOriginAmount: "200",
FixedFee: "10",
},
},
}

err := c.client.PutBulkQuotes(c.GetTestContext(), &req)
c.Require().NoError(err)

quotes, err := c.client.GetAllQuotes(c.GetTestContext())
c.Require().NoError(err)

expectedResp := []model.GetQuoteResponse{
{
OriginChainID: 1,
OriginTokenAddr: "0xOriginTokenAddr",
DestChainID: 42161,
DestTokenAddr: "0xDestTokenAddr",
DestAmount: "100",
MaxOriginAmount: "200",
FixedFee: "10",
RelayerAddr: c.testWallet.Address().String(),
UpdatedAt: quotes[0].UpdatedAt,
},
{
OriginChainID: 42161,
OriginTokenAddr: "0xOriginTokenAddr",
DestChainID: 1,
DestTokenAddr: "0xDestTokenAddr",
DestAmount: "100",
MaxOriginAmount: "200",
FixedFee: "10",
RelayerAddr: c.testWallet.Address().String(),
UpdatedAt: quotes[0].UpdatedAt,
},
}
c.Len(quotes, 2)
c.Equal(expectedResp[0], *quotes[0])
c.Equal(expectedResp[1], *quotes[1])
}
Comment on lines +41 to +98
Copy link
Contributor

Choose a reason for hiding this comment

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

Address implicit memory aliasing.

The loop in TestPutAndGetBulkQuotes contains implicit memory aliasing. To avoid this, create a new variable inside the loop.

for _, quoteReq := range putRequest.Quotes {
	dbQuote, err := parseDBQuote(&quoteReq, relayerAddr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid quote request"})
		return
	}
	dbQuotes = append(dbQuotes, dbQuote)
}
for i := range putRequest.Quotes {
	quoteReq := putRequest.Quotes[i]
	dbQuote, err := parseDBQuote(&quoteReq, relayerAddr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid quote request"})
		return
	}
	dbQuotes = append(dbQuotes, dbQuote)
}


func (c *ClientSuite) TestGetSpecificQuote() {
req := model.PutQuoteRequest{
OriginChainID: 1,
Expand Down
2 changes: 2 additions & 0 deletions services/rfq/api/db/api_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ type APIDBReader interface {
type APIDBWriter interface {
// UpsertQuote upserts a quote in the database.
UpsertQuote(ctx context.Context, quote *Quote) error
// UpsertQuotes upserts multiple quotes in the database.
UpsertQuotes(ctx context.Context, quotes []*Quote) error
}

// APIDB is the interface for the database service.
Expand Down
14 changes: 14 additions & 0 deletions services/rfq/api/db/sql/base/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package base
import (
"context"
"fmt"

"gorm.io/gorm/clause"

"github.com/synapsecns/sanguine/services/rfq/api/db"
Expand Down Expand Up @@ -63,3 +64,16 @@ func (s *Store) UpsertQuote(ctx context.Context, quote *db.Quote) error {
}
return nil
}

// UpsertQuotes inserts multiple quotes into the database or updates existing ones.
func (s *Store) UpsertQuotes(ctx context.Context, quotes []*db.Quote) error {
dbTx := s.DB().WithContext(ctx).
Clauses(clause.OnConflict{
UpdateAll: true,
}).Create(quotes)

if dbTx.Error != nil {
return fmt.Errorf("could not update quotes: %w", dbTx.Error)
}
return nil
}
42 changes: 42 additions & 0 deletions services/rfq/api/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,37 @@ const docTemplate = `{
}
}
},
"/bulk_quotes": {
"put": {
"description": "upsert bulk quotes from relayer.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"quotes"
],
"summary": "Upsert quotes",
"parameters": [
{
"description": "query params",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.PutBulkQuotesRequest"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/quotes": {
"get": {
"description": "get quotes from all relayers.",
Expand Down Expand Up @@ -184,6 +215,17 @@ const docTemplate = `{
}
}
},
"model.PutBulkQuotesRequest": {
"type": "object",
"properties": {
"quotes": {
"type": "array",
"items": {
"$ref": "#/definitions/model.PutQuoteRequest"
}
}
}
},
"model.PutQuoteRequest": {
"type": "object",
"properties": {
Expand Down
42 changes: 42 additions & 0 deletions services/rfq/api/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,37 @@
}
}
},
"/bulk_quotes": {
"put": {
"description": "upsert bulk quotes from relayer.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"quotes"
],
"summary": "Upsert quotes",
"parameters": [
{
"description": "query params",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.PutBulkQuotesRequest"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/quotes": {
"get": {
"description": "get quotes from all relayers.",
Expand Down Expand Up @@ -173,6 +204,17 @@
}
}
},
"model.PutBulkQuotesRequest": {
"type": "object",
"properties": {
"quotes": {
"type": "array",
"items": {
"$ref": "#/definitions/model.PutQuoteRequest"
}
}
}
},
"model.PutQuoteRequest": {
"type": "object",
"properties": {
Expand Down
27 changes: 27 additions & 0 deletions services/rfq/api/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ definitions:
description: UpdatedAt is the time that the quote was last upserted
type: string
type: object
model.PutBulkQuotesRequest:
properties:
quotes:
items:
$ref: '#/definitions/model.PutQuoteRequest'
type: array
type: object
model.PutQuoteRequest:
properties:
dest_amount:
Expand Down Expand Up @@ -87,6 +94,26 @@ paths:
summary: Relay ack
tags:
- ack
/bulk_quotes:
put:
consumes:
- application/json
description: upsert bulk quotes from relayer.
parameters:
- description: query params
in: body
name: request
required: true
schema:
$ref: '#/definitions/model.PutBulkQuotesRequest'
produces:
- application/json
responses:
"200":
description: OK
summary: Upsert quotes
tags:
- quotes
/quotes:
get:
consumes:
Expand Down
5 changes: 5 additions & 0 deletions services/rfq/api/model/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ type PutQuoteRequest struct {
DestFastBridgeAddress string `json:"dest_fast_bridge_address"`
}

// PutBulkQuotesRequest contains the schema for a PUT /quote request.
type PutBulkQuotesRequest struct {
Quotes []PutQuoteRequest `json:"quotes"`
}

// PutAckRequest contains the schema for a PUT /ack request.
type PutAckRequest struct {
TxID string `json:"tx_id"`
Expand Down
Loading
Loading