-
Notifications
You must be signed in to change notification settings - Fork 32
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
Add relayer API #1785
Add relayer API #1785
Changes from 40 commits
eb4c98e
0129b41
c740fbf
571e865
521e7fa
2e2eba3
de99481
20123b6
29a27d7
90d1f5f
8645575
902f4aa
86d01e7
8689d37
a7a9cf2
165f46f
c352481
5e3f0a7
ee218b2
a5b254f
b99e4fa
27b7998
d75654b
32db813
833fca4
acd3f44
aa743d2
831c50d
1cca179
5ca7680
f42f2ce
dbed1e3
2c57477
0d0615c
4e4e4d4
9abe98c
49b6ce4
98dcf6b
83aa7d9
51f719d
497bdff
6a297fb
5dbd12e
5fa3598
6beb0f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,9 +23,9 @@ import ( | |
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" | ||
) | ||
|
||
// APIServer is a struct that holds the configuration, database connection, gin engine, RPC client, metrics handler, and fast bridge contracts. | ||
// QuoterAPIServer is a struct that holds the configuration, database connection, gin engine, RPC client, metrics handler, and fast bridge contracts. | ||
// It is used to initialize and run the API server. | ||
type APIServer struct { | ||
type QuoterAPIServer struct { | ||
cfg config.Config | ||
db db.APIDB | ||
engine *gin.Engine | ||
|
@@ -42,7 +42,7 @@ func NewAPI( | |
handler metrics.Handler, | ||
omniRPCClient omniClient.RPCClient, | ||
store db.APIDB, | ||
) (*APIServer, error) { | ||
) (*QuoterAPIServer, error) { | ||
if ctx == nil { | ||
return nil, fmt.Errorf("context is nil") | ||
} | ||
|
@@ -68,7 +68,7 @@ func NewAPI( | |
} | ||
} | ||
|
||
return &APIServer{ | ||
return &QuoterAPIServer{ | ||
cfg: cfg, | ||
db: store, | ||
omnirpcClient: omniRPCClient, | ||
|
@@ -84,8 +84,8 @@ const ( | |
|
||
var logger = log.Logger("rfq-api") | ||
|
||
// Run runs the rest api server. | ||
func (r *APIServer) Run(ctx context.Context) error { | ||
// Run runs the quoter api server. | ||
func (r *QuoterAPIServer) Run(ctx context.Context) error { | ||
// TODO: Use Gin Helper | ||
engine := ginhelper.New(logger) | ||
h := NewHandler(r.db) | ||
|
@@ -112,7 +112,7 @@ func (r *APIServer) Run(ctx context.Context) error { | |
} | ||
|
||
// AuthMiddleware is the Gin authentication middleware that authenticates requests using EIP191. | ||
func (r *APIServer) AuthMiddleware() gin.HandlerFunc { | ||
func (r *QuoterAPIServer) AuthMiddleware() gin.HandlerFunc { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
return func(c *gin.Context) { | ||
var req model.PutQuoteRequest | ||
if err := c.BindJSON(&req); err != nil { | ||
Comment on lines
112
to
118
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The |
||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -15,9 +15,9 @@ import ( | |||||||||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/api/model" | ||||||||||||||||||||||
) | ||||||||||||||||||||||
|
||||||||||||||||||||||
func (c *ServerSuite) TestNewAPIServer() { | ||||||||||||||||||||||
func (c *ServerSuite) TestNewQuoterAPIServer() { | ||||||||||||||||||||||
// Start the API server in a separate goroutine and wait for it to initialize. | ||||||||||||||||||||||
c.startAPIServer() | ||||||||||||||||||||||
c.startQuoterAPIServer() | ||||||||||||||||||||||
client := &http.Client{} | ||||||||||||||||||||||
req, err := http.NewRequestWithContext(c.GetTestContext(), http.MethodGet, fmt.Sprintf("http://localhost:%d/quotes", c.port), nil) | ||||||||||||||||||||||
c.Require().NoError(err) | ||||||||||||||||||||||
|
@@ -34,7 +34,7 @@ func (c *ServerSuite) TestNewAPIServer() { | |||||||||||||||||||||
// TestEIP191_SuccessfulSignature tests the EIP191 signature process for successful authentication. | ||||||||||||||||||||||
func (c *ServerSuite) TestEIP191_SuccessfulSignature() { | ||||||||||||||||||||||
// Start the API server in a separate goroutine and wait for it to initialize. | ||||||||||||||||||||||
c.startAPIServer() | ||||||||||||||||||||||
c.startQuoterAPIServer() | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Prepare the authorization header with a signed timestamp. | ||||||||||||||||||||||
header, err := c.prepareAuthHeader(c.testWallet) | ||||||||||||||||||||||
|
@@ -65,7 +65,7 @@ func (c *ServerSuite) TestEIP191_SuccessfulSignature() { | |||||||||||||||||||||
// TestEIP191_UnsuccessfulSignature tests the EIP191 signature process with an incorrect wallet signature. | ||||||||||||||||||||||
func (c *ServerSuite) TestEIP191_UnsuccessfulSignature() { | ||||||||||||||||||||||
// Start the API server in a separate goroutine and wait for it to initialize. | ||||||||||||||||||||||
c.startAPIServer() | ||||||||||||||||||||||
c.startQuoterAPIServer() | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Prepare the authorization header with a signed timestamp using an incorrect wallet. | ||||||||||||||||||||||
randomWallet, err := wallet.FromRandom() | ||||||||||||||||||||||
|
@@ -97,7 +97,7 @@ func (c *ServerSuite) TestEIP191_UnsuccessfulSignature() { | |||||||||||||||||||||
// TestEIP191_SuccessfulPutSubmission tests a successful PUT request submission. | ||||||||||||||||||||||
func (c *ServerSuite) TestEIP191_SuccessfulPutSubmission() { | ||||||||||||||||||||||
// Start the API server in a separate goroutine and wait for it to initialize. | ||||||||||||||||||||||
c.startAPIServer() | ||||||||||||||||||||||
c.startQuoterAPIServer() | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Prepare the authorization header with a signed timestamp. | ||||||||||||||||||||||
header, err := c.prepareAuthHeader(c.testWallet) | ||||||||||||||||||||||
|
@@ -120,7 +120,7 @@ func (c *ServerSuite) TestEIP191_SuccessfulPutSubmission() { | |||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
func (c *ServerSuite) TestPutAndGetQuote() { | ||||||||||||||||||||||
c.startAPIServer() | ||||||||||||||||||||||
c.startQuoterAPIServer() | ||||||||||||||||||||||
|
||||||||||||||||||||||
header, err := c.prepareAuthHeader(c.testWallet) | ||||||||||||||||||||||
c.Require().NoError(err) | ||||||||||||||||||||||
|
@@ -162,7 +162,7 @@ func (c *ServerSuite) TestPutAndGetQuote() { | |||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
func (c *ServerSuite) TestPutAndGetQuoteByRelayer() { | ||||||||||||||||||||||
c.startAPIServer() | ||||||||||||||||||||||
c.startQuoterAPIServer() | ||||||||||||||||||||||
|
||||||||||||||||||||||
header, err := c.prepareAuthHeader(c.testWallet) | ||||||||||||||||||||||
c.Require().NoError(err) | ||||||||||||||||||||||
|
@@ -203,10 +203,10 @@ func (c *ServerSuite) TestPutAndGetQuoteByRelayer() { | |||||||||||||||||||||
c.Assert().True(found, "Newly added quote not found") | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
// startAPIServer starts the API server and waits for it to initialize. | ||||||||||||||||||||||
func (c *ServerSuite) startAPIServer() { | ||||||||||||||||||||||
// startQuoterAPIServer starts the API server and waits for it to initialize. | ||||||||||||||||||||||
func (c *ServerSuite) startQuoterAPIServer() { | ||||||||||||||||||||||
go func() { | ||||||||||||||||||||||
err := c.APIServer.Run(c.GetTestContext()) | ||||||||||||||||||||||
err := c.QuoterAPIServer.Run(c.GetTestContext()) | ||||||||||||||||||||||
Comment on lines
+206
to
+209
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The - time.Sleep(2 * time.Second) // Wait for the server to start.
+ // Implement a more reliable way to wait for the server to start, such as polling a health endpoint. Committable suggestion
Suggested change
|
||||||||||||||||||||||
c.Require().NoError(err) | ||||||||||||||||||||||
}() | ||||||||||||||||||||||
time.Sleep(2 * time.Second) // Wait for the server to start. | ||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,91 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Package chain defines the interface for interacting with a blockchain. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
package chain | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"context" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"fmt" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"math/big" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/ethereum/go-ethereum/common" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/ethereum/go-ethereum/core/types" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/synapsecns/sanguine/core" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/synapsecns/sanguine/ethergo/client" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/synapsecns/sanguine/ethergo/submitter" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/relayer/listener" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/relayer/reldb" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Chain is a chain helper for relayer. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// lowercase fields are private, uppercase are public. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// the plan is to move this out of relayer which is when this distinction will matter. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type Chain struct { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ChainID uint32 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Bridge *fastbridge.FastBridgeRef | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Client client.EVM | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Confirmations uint64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
listener listener.ContractListener | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
submitter submitter.TransactionSubmitter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// NewChain creates a new chain. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
func NewChain(ctx context.Context, chainClient client.EVM, addr common.Address, chainListener listener.ContractListener, ts submitter.TransactionSubmitter) (*Chain, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bridge, err := fastbridge.NewFastBridgeRef(addr, chainClient) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return nil, fmt.Errorf("could not create bridge contract: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
chainID, err := chainClient.ChainID(ctx) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return nil, fmt.Errorf("could not get chain id: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return &Chain{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ChainID: uint32(chainID.Int64()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Bridge: bridge, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Client: chainClient, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// TODO: configure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Confirmations: 1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
listener: chainListener, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
submitter: ts, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+32
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The - // TODO: configure
- Confirmations: 1,
+ // TODO: This value should be made configurable.
+ Confirmations: defaultConfirmations, // Assuming `defaultConfirmations` is a constant defined elsewhere. Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// SubmitTransaction submits a transaction to the chain. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
func (c Chain) SubmitTransaction(ctx context.Context, call submitter.ContractCallType) (nonce uint64, _ error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//nolint: wrapcheck | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return c.submitter.SubmitTransaction(ctx, big.NewInt(int64(c.ChainID)), call) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// LatestBlock returns the latest block. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
func (c Chain) LatestBlock() uint64 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return c.listener.LatestBlock() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// SubmitRelay submits a relay transaction to the destination chain after evaluating gas amount. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
func (c Chain) SubmitRelay(ctx context.Context, request reldb.QuoteRequest) (uint64, *big.Int, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
gasAmount := big.NewInt(0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
var err error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if request.Transaction.SendChainGas { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
gasAmount, err = c.Bridge.ChainGasAmount(&bind.CallOpts{Context: ctx}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return 0, nil, fmt.Errorf("could not get chain gas amount: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
nonce, err := c.SubmitTransaction(ctx, func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
transactor.Value = core.CopyBigInt(gasAmount) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tx, err = c.Bridge.Relay(transactor, request.RawRequest) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return nil, fmt.Errorf("could not relay: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return tx, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return 0, nil, fmt.Errorf("could not submit transaction: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return nonce, gasAmount, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
SetupTest
method correctly initializes theQuoterAPIServer
and starts it in a goroutine. The use oftime.Sleep
to wait for the server to start is not ideal for test reliability. Consider using a more deterministic approach to wait for the server to be ready, such as polling on a health check endpoint.Committable suggestion