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
244 changes: 244 additions & 0 deletions docs/bridge/docs/rfq/API/upsert-quotes.api.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
---
id: upsert-quotes
title: "Upsert quotes"
description: "upsert bulk quotes from relayer."
sidebar_label: "Upsert quotes"
hide_title: true
hide_table_of_contents: true
api: eJyNVMGOmzAQ/RXkc9pEPea4VU89tKo2p3SFBhjAG8DesdkNQvx7ZzDZ0IRFCxIy4+fx87w37lWGLiVtvTaN2qvWOiQfJW11il5a49FFOZk6IqygQ/qqNorwpUXnH0zWqX2vUtN4bLwMwdpKpyCpts9O8vXKpSXWICNLxnJujU7+QnIZaY+1uwcwLx9DbdqQ23cWmZ/zpJtCDZswn5agm1hnM4RmOgXSOyQH/iSkswJjyDJC5z7O580JmxG2iMn1GbM4R1ycreEcG9IFM1rhPSHWmU+gz3Kf4KvsGTZFTPKMqVfXABBBt4QYQl1m/mDpqYssELBmwQuakE/hqcVBAs6axgUJv+12k5KzDL9+hp2gYMzx4oMnLh/60nAmZVvPqS34kn+2YsV4Qm2U2OrP1YA/zlDbCueGOt5Y51KAO8fs1gxys2pe2evUzA7X4IILrpN34u/Wtb5buURkeOJ66iY3l3aEVKwnRdZeiqN4/SuSCwKI8NY4X8PYoA3UAjmExn8v9H+izbr8MzfE5CKPZ7+1FR9VtmypGpt8lPWo5rKy+CUTknDfJ+DwQNUwSHi0G8d5+AqkIZHjHOW8JULGvSJyn5Ah6ntg+OVRNhd41Y7evr2ThrnVfh8eGZtMV1ltMllC8CbW5u9e/eVXqj8WYjT1GO9VBU3RQiH4kFaefxaR3uo=
sidebar_class_name: "put api-method"
custom_edit_url: null
---

import ApiTabs from "@theme/ApiTabs";
import DiscriminatorTabs from "@theme/DiscriminatorTabs";
import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
import SecuritySchemes from "@theme/ApiExplorer/SecuritySchemes";
import MimeTabs from "@theme/MimeTabs";
import ParamsItem from "@theme/ParamsItem";
import ResponseSamples from "@theme/ResponseSamples";
import SchemaItem from "@theme/SchemaItem";
import SchemaTabs from "@theme/SchemaTabs";
import Markdown from "@theme/Markdown";
import Heading from "@theme/Heading";
import OperationTabs from "@theme/OperationTabs";
import TabItem from "@theme/TabItem";

<Heading
as={"h1"}
className={"openapi__heading"}
children={"Upsert quotes"}
>
</Heading>

<MethodEndpoint
method={"put"}
path={"/bulk_quotes"}
>

</MethodEndpoint>



upsert bulk quotes from relayer.

<Heading
id={"request"}
as={"h2"}
className={"openapi-tabs__heading"}
children={"Request"}
>
</Heading>

<MimeTabs
className={"openapi-tabs__mime"}
>
<TabItem
label={"application/json"}
value={"application/json-schema"}
>
<details
style={{}}
className={"openapi-markdown__details mime"}
data-collapsed={false}
open={true}
>
<summary
style={{}}
className={"openapi-markdown__details-summary-mime"}
>
<h3
className={"openapi-markdown__details-summary-header-body"}
>
Body
</h3><strong
className={"openapi-schema__required"}
>
required
</strong>
</summary><div
style={{"textAlign":"left","marginLeft":"1rem"}}
>
<div
style={{"marginTop":"1rem","marginBottom":"1rem"}}
>


query params


</div>
</div><ul
style={{"marginLeft":"1rem"}}
>
<SchemaItem
collapsible={true}
className={"schemaItem"}
>
<details
style={{}}
className={"openapi-markdown__details"}
>
<summary
style={{}}
>
<span
className={"openapi-schema__container"}
>
<strong
className={"openapi-schema__property"}
>
quotes
</strong><span
className={"openapi-schema__name"}
>
object[]
</span>
</span>
</summary><div
style={{"marginLeft":"1rem"}}
>
<li>
<div
style={{"fontSize":"var(--ifm-code-font-size)","opacity":"0.6","marginLeft":"-.5rem","paddingBottom":".5rem"}}
>
Array [
</div>
</li><SchemaItem
collapsible={false}
name={"dest_amount"}
required={false}
schemaName={"string"}
qualifierMessage={undefined}
schema={{"type":"string"}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"dest_chain_id"}
required={false}
schemaName={"integer"}
qualifierMessage={undefined}
schema={{"type":"integer"}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"dest_fast_bridge_address"}
required={false}
schemaName={"string"}
qualifierMessage={undefined}
schema={{"type":"string"}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"dest_token_addr"}
required={false}
schemaName={"string"}
qualifierMessage={undefined}
schema={{"type":"string"}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"fixed_fee"}
required={false}
schemaName={"string"}
qualifierMessage={undefined}
schema={{"type":"string"}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"max_origin_amount"}
required={false}
schemaName={"string"}
qualifierMessage={undefined}
schema={{"type":"string"}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"origin_chain_id"}
required={false}
schemaName={"integer"}
qualifierMessage={undefined}
schema={{"type":"integer"}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"origin_fast_bridge_address"}
required={false}
schemaName={"string"}
qualifierMessage={undefined}
schema={{"type":"string"}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"origin_token_addr"}
required={false}
schemaName={"string"}
qualifierMessage={undefined}
schema={{"type":"string"}}
>

</SchemaItem><li>
<div
style={{"fontSize":"var(--ifm-code-font-size)","opacity":"0.6","marginLeft":"-.5rem"}}
>
]
</div>
</li>
</div>
</details>
</SchemaItem>
</ul>
</details>
</TabItem>
</MimeTabs><div>
<div>
<ApiTabs
label={undefined}
id={undefined}
>
<TabItem
label={"200"}
value={"200"}
>
<div>


OK


</div><div>

</div>
</TabItem>
</ApiTabs>
</div>
</div>

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
17 changes: 9 additions & 8 deletions services/rfq/api/client/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ func NewTestClientSuite(tb testing.TB) *ClientSuite {
func (c *ClientSuite) SetupTest() {
c.TestSuite.SetupTest()

metricsHandler := metrics.NewNullHandler()
c.handler = metricsHandler
dbType, err := dbcommon.DBTypeFromString("sqlite")
c.Require().NoError(err)
// TODO use temp file / in memory sqlite3 to not create in directory files
testDB, err := sql.Connect(c.GetSuiteContext(), dbType, filet.TmpDir(c.T(), ""), metricsHandler)
c.Require().NoError(err)
c.database = testDB
Comment on lines +63 to +68
Copy link
Contributor

Choose a reason for hiding this comment

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

Correct Initialization of testDB

The initialization of testDB is correct. However, the TODO comment should be addressed.

-  // TODO use temp file / in memory sqlite3 to not create in directory files

Consider using a temporary file or in-memory sqlite3 to avoid creating files in the directory.


Would you like me to address this TODO comment and update the code accordingly?

<!-- This is an auto-generated comment by CodeRabbit -->


testOmnirpc := omnirpcHelper.NewOmnirpcServer(c.GetTestContext(), c.T(), c.omniRPCTestBackends...)
omniRPCClient := omniClient.NewOmnirpcClient(testOmnirpc, c.handler, omniClient.WithCaptureReqRes())
c.omniRPCClient = omniRPCClient
Expand Down Expand Up @@ -175,14 +184,6 @@ func (c *ClientSuite) SetupSuite() {
c.T().Fatal(err)
}

dbType, err := dbcommon.DBTypeFromString("sqlite")
c.Require().NoError(err)
metricsHandler := metrics.NewNullHandler()
c.handler = metricsHandler
// TODO use temp file / in memory sqlite3 to not create in directory files
testDB, err := sql.Connect(c.GetSuiteContext(), dbType, filet.TmpDir(c.T(), ""), metricsHandler)
c.Require().NoError(err)
c.database = testDB
// setup config
}

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
Loading
Loading