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: mimimal viable withdrawal api #2815

Merged
merged 12 commits into from
Jul 2, 2024
8 changes: 7 additions & 1 deletion ethergo/submitter/submitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

var logger = log.Logger("ethergo-submitter")

const meterName = "github.com/synapsecns/sanguine/services/rfq/api/rest"
const meterName = "github.com/synapsecns/sanguine/ethergo/submitter"

// TransactionSubmitter is the interface for submitting transactions to the chain.
type TransactionSubmitter interface {
Expand All @@ -51,6 +51,8 @@
SubmitTransaction(ctx context.Context, chainID *big.Int, call ContractCallType) (nonce uint64, err error)
// GetSubmissionStatus returns the status of a transaction and any metadata associated with it if it is complete.
GetSubmissionStatus(ctx context.Context, chainID *big.Int, nonce uint64) (status SubmissionStatus, err error)
// Address returns the address of the signer.
Address() common.Address
}

// txSubmitterImpl is the implementation of the transaction submitter.
Expand Down Expand Up @@ -683,4 +685,8 @@
return gasEstimate, nil
}

func (t *txSubmitterImpl) Address() common.Address {
return t.signer.Address()

Check warning on line 689 in ethergo/submitter/submitter.go

View check run for this annotation

Codecov / codecov/patch

ethergo/submitter/submitter.go#L688-L689

Added lines #L688 - L689 were not covered by tests
}

var _ TransactionSubmitter = &txSubmitterImpl{}
22 changes: 22 additions & 0 deletions services/rfq/relayer/relapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
GetQuoteRequestStatusByTxHash(ctx context.Context, hash string) (*GetQuoteRequestStatusResponse, error)
GetQuoteRequestStatusByTxID(ctx context.Context, hash string) (*GetQuoteRequestStatusResponse, error)
RetryTransaction(ctx context.Context, txhash string) (*GetTxRetryResponse, error)
Withdraw(ctx context.Context, req *WithdrawRequest) (*WithdrawResponse, error)
}

type relayerClient struct {
Expand Down Expand Up @@ -100,3 +101,24 @@

return &res, nil
}

// WithdrawResponse is the response for the withdraw request.
type WithdrawResponse struct {
Nonce uint64 `json:"nonce"`
}
trajan0x marked this conversation as resolved.
Show resolved Hide resolved

func (r *relayerClient) Withdraw(ctx context.Context, req *WithdrawRequest) (*WithdrawResponse, error) {
var res WithdrawResponse
resp, err := r.client.R().SetContext(ctx).
SetResult(&res).
SetBody(req).
Post(postWithdrawRoute)
if err != nil {
return nil, fmt.Errorf("failed to withdraw transaction: %w", err)
}

Check warning on line 118 in services/rfq/relayer/relapi/client.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/client.go#L117-L118

Added lines #L117 - L118 were not covered by tests
if resp.StatusCode() != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode())
}

Check warning on line 121 in services/rfq/relayer/relapi/client.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/client.go#L120-L121

Added lines #L120 - L121 were not covered by tests

return &res, nil
trajan0x marked this conversation as resolved.
Show resolved Hide resolved
}
165 changes: 158 additions & 7 deletions services/rfq/relayer/relapi/handler.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package relapi

import (
"encoding/json"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/synapsecns/sanguine/ethergo/submitter"
"github.com/synapsecns/sanguine/services/rfq/contracts/ierc20"
"github.com/synapsecns/sanguine/services/rfq/relayer/relconfig"
"math/big"
"net/http"

"github.com/ethereum/go-ethereum/common"
Expand All @@ -13,15 +21,19 @@

// Handler is the REST API handler.
type Handler struct {
db reldb.Service
chains map[uint32]*chain.Chain
db reldb.Service
chains map[uint32]*chain.Chain
cfg relconfig.Config
submitter submitter.TransactionSubmitter
Comment on lines +27 to +28
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure the new fields in the Handler struct are properly initialized.

The addition of new fields should be tested to ensure they are correctly initialized and used.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

}

// NewHandler creates a new REST API handler.
func NewHandler(db reldb.Service, chains map[uint32]*chain.Chain) *Handler {
func NewHandler(db reldb.Service, chains map[uint32]*chain.Chain, cfg relconfig.Config, txSubmitter submitter.TransactionSubmitter) *Handler {
return &Handler{
db: db, // Store the database connection in the handler
chains: chains,
db: db, // Store the database connection in the handler
chains: chains,
cfg: cfg,
submitter: txSubmitter,
Comment on lines +32 to +37
Copy link
Contributor

Choose a reason for hiding this comment

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

Tip

Codebase Verification

The NewHandler function is not covered by tests.

The search through the test files did not yield any results for the NewHandler function, indicating that it is not covered by unit tests. Please ensure that unit tests are added to cover various scenarios for this function.

  • Add unit tests for the NewHandler function.
Analysis chain

Ensure the NewHandler function is covered by tests.

The NewHandler function now includes additional parameters. Ensure that the function is covered by unit tests for various scenarios.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify if the NewHandler function is covered by tests.

# Test: Search for the usage of NewHandler in test files. Expect: Occurrences in test files.
rg --type go --glob '*_test.go' $'NewHandler'

Length of output: 44



Script:

#!/bin/bash
# Description: Verify if the NewHandler function is indirectly covered by tests.

# Test: Search for test functions that might indirectly call or cover the NewHandler function.
# First, list all test files
test_files=$(fd --type f --glob '*_test.go')

# Then search for the term 'NewHandler' within these test files
for file in $test_files; do
    echo "Searching in $file"
    rg 'NewHandler' $file
done

Length of output: 75358

Comment on lines +32 to +37
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure the NewHandler function is covered by tests.

The addition of new parameters should be tested to ensure the function works as expected.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

}
}

Expand Down Expand Up @@ -107,14 +119,14 @@
}

chainID := quoteRequest.Transaction.DestChainId
chain, ok := h.chains[chainID]
chainHandler, ok := h.chains[chainID]
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure the chainHandler variable is covered by tests.

The renaming of the variable should be tested to ensure it does not introduce any issues.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("No contract found for chain: %d", chainID)})
return
}

// `quoteRequest == nil` case should be handled by the db query above
nonce, gasAmount, err := chain.SubmitRelay(c, *quoteRequest)
nonce, gasAmount, err := chainHandler.SubmitRelay(c, *quoteRequest)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("could not submit relay: %s", err.Error())})
return
Expand All @@ -128,3 +140,142 @@
}
c.JSON(http.StatusOK, resp)
}

// Withdraw withdraws tokens from the relayer.
func (h *Handler) Withdraw(c *gin.Context) {
var req WithdrawRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

Check warning on line 150 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L148-L150

Added lines #L148 - L150 were not covered by tests
trajan0x marked this conversation as resolved.
Show resolved Hide resolved

// validate the token address
if !tokenIDExists(h.cfg, req.TokenAddress, int(req.ChainID)) {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("invalid token address %s for chain %d", req.TokenAddress.Hex(), req.ChainID)})
return
}

Check warning on line 156 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L154-L156

Added lines #L154 - L156 were not covered by tests
trajan0x marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +157 to +159
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 29, 2024

Choose a reason for hiding this comment

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

Add tests for tokenIDExists validation.

The validation of the token address in the Withdraw function is not covered by tests. Ensure that this validation is tested for various scenarios.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 153-155: services/rfq/relayer/relapi/handler.go#L153-L155
Added lines #L153 - L155 were not covered by tests

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure

Copy link
Contributor

Choose a reason for hiding this comment

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

@trajan0x, here are the unit tests for the tokenIDExists validation:

package relapi_test

import (
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/synapsecns/sanguine/services/rfq/relayer/relconfig"
	"github.com/synapsecns/sanguine/services/rfq/relayer/relapi"
	"github.com/stretchr/testify/assert"
)

func TestTokenIDExists(t *testing.T) {
	cfg := relconfig.Config{
		QuotableTokens: map[string]struct{}{
			"1:0xTokenAddress1": {},
			"2:0xTokenAddress2": {},
		},
	}

	tests := []struct {
		name         string
		tokenAddress common.Address
		chainID      int
		expected     bool
	}{
		{
			name:         "Token exists",
			tokenAddress: common.HexToAddress("0xTokenAddress1"),
			chainID:      1,
			expected:     true,
		},
		{
			name:         "Token does not exist",
			tokenAddress: common.HexToAddress("0xNonExistentToken"),
			chainID:      1,
			expected:     false,
		},
		{
			name:         "Multiple tokens, correct token",
			tokenAddress: common.HexToAddress("0xTokenAddress2"),
			chainID:      2,
			expected:     true,
		},
		{
			name:         "Multiple tokens, incorrect token",
			tokenAddress: common.HexToAddress("0xTokenAddress1"),
			chainID:      2,
			expected:     false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := relapi.TokenIDExists(cfg, tt.tokenAddress, tt.chainID)
			assert.Equal(t, tt.expected, result)
		})
	}
}

This code tests various scenarios to ensure that the tokenIDExists function works as expected. Let me know if you need any further modifications or additional tests.


Learnings added
Learnt from: trajan0x
PR: synapsecns/sanguine#2815
File: services/rfq/relayer/relapi/handler.go:154-156
Timestamp: 2024-06-29T05:11:50.785Z
Learning: When adding new validation logic in the `Withdraw` function, ensure to cover it with unit tests to handle various scenarios.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

trajan0x marked this conversation as resolved.
Show resolved Hide resolved

// validate the withdrawal address
if !toAddressIsWhitelisted(h.cfg, req.To) {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("withdrawal address %s is not whitelisted", req.To.Hex())})
return
}

Check warning on line 162 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L160-L162

Added lines #L160 - L162 were not covered by tests
Comment on lines +162 to +165
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 29, 2024

Choose a reason for hiding this comment

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

Add tests for toAddressIsWhitelisted validation.

The validation of the withdrawal address in the Withdraw function is not covered by tests. Ensure that this validation is tested for various scenarios.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 158-161: services/rfq/relayer/relapi/handler.go#L158-L161
Added lines #L158 - L161 were not covered by tests

Copy link
Contributor Author

Choose a reason for hiding this comment

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

can you generate?

Copy link
Contributor

Choose a reason for hiding this comment

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

@trajan0x, sure! Here are the unit tests for the toAddressIsWhitelisted validation in the Withdraw function:

package relapi_test

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"github.com/synapsecns/sanguine/services/rfq/relayer/relapi"
	"github.com/synapsecns/sanguine/services/rfq/relayer/relconfig"
	"github.com/synapsecns/sanguine/services/rfq/relayer/reldb"
	"github.com/synapsecns/sanguine/ethergo/submitter"
)

func TestWithdrawAddressWhitelist(t *testing.T) {
	gin.SetMode(gin.TestMode)

	// Create a mock configuration with a whitelist
	cfg := relconfig.Config{
		WithdrawalWhitelist: []string{
			"0x1111111111111111111111111111111111111111",
			"0x2222222222222222222222222222222222222222",
		},
	}

	// Create a mock handler with the mock configuration
	handler := relapi.NewHandler(reldb.NewMockService(), nil, cfg, submitter.NewMockTransactionSubmitter())

	tests := []struct {
		name       string
		toAddress  common.Address
		statusCode int
	}{
		{
			name:       "Address is whitelisted",
			toAddress:  common.HexToAddress("0x1111111111111111111111111111111111111111"),
			statusCode: http.StatusOK,
		},
		{
			name:       "Address is not whitelisted",
			toAddress:  common.HexToAddress("0x3333333333333333333333333333333333333333"),
			statusCode: http.StatusBadRequest,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			reqBody := relapi.WithdrawRequest{
				ChainID:      1,
				Amount:       "1000000000000000000", // 1 ETH in wei
				TokenAddress: common.HexToAddress("0x0000000000000000000000000000000000000000"),
				To:           tt.toAddress,
			}
			body, err := json.Marshal(reqBody)
			assert.NoError(t, err)

			req, err := http.NewRequest(http.MethodPost, "/withdraw", bytes.NewBuffer(body))
			assert.NoError(t, err)
			req.Header.Set("Content-Type", "application/json")

			rec := httptest.NewRecorder()
			c, _ := gin.CreateTestContext(rec)
			c.Request = req

			handler.Withdraw(c)

			assert.Equal(t, tt.statusCode, rec.Code)
		})
	}
}

This test suite covers the validation of the withdrawal address in the Withdraw function by testing both whitelisted and non-whitelisted addresses.


Learnings added
Learnt from: trajan0x
PR: synapsecns/sanguine#2815
File: services/rfq/relayer/relapi/handler.go:162-165
Timestamp: 2024-07-02T14:43:19.123Z
Learning: When adding new validation logic in the `Withdraw` function, ensure to cover it with unit tests to handle various scenarios, including valid and invalid addresses.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


Learnings used
Learnt from: trajan0x
PR: synapsecns/sanguine#2815
File: services/rfq/relayer/relapi/handler.go:154-156
Timestamp: 2024-06-29T05:11:50.952Z
Learning: When adding new validation logic in the `Withdraw` function, ensure to cover it with unit tests to handle various scenarios.

Learnt from: trajan0x
PR: synapsecns/sanguine#2815
File: services/rfq/relayer/relapi/handler.go:153-156
Timestamp: 2024-06-29T05:12:50.268Z
Learning: When adding new validation logic in the `Withdraw` function, ensure to cover it with unit tests to handle various scenarios.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

running the whole api for this is crazy. export it

Copy link
Contributor

Choose a reason for hiding this comment

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

@trajan0x, I understand your concern. We can export the toAddressIsWhitelisted function to facilitate direct testing. Here are the proposed changes:

  1. Export the toAddressIsWhitelisted function:

    // Export the function by renaming it to `ToAddressIsWhitelisted`.
    func ToAddressIsWhitelisted(cfg relconfig.Config, to common.Address) bool {
        for _, addr := range cfg.WithdrawalWhitelist {
            if common.HexToAddress(addr) == to {
                return true;
            }
        }
        return false;
    }
  2. Update the Withdraw function to use the exported function:

    // Update the function call in the Withdraw method.
    if !ToAddressIsWhitelisted(h.cfg, req.To) {
        c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("withdrawal address %s is not whitelisted", req.To.Hex())})
        return;
    }
  3. Unit tests for the ToAddressIsWhitelisted function:

    package relapi_test
    
    import (
        "testing"
    
        "github.com/ethereum/go-ethereum/common"
        "github.com/stretchr/testify/assert"
        "github.com/synapsecns/sanguine/services/rfq/relayer/relapi"
        "github.com/synapsecns/sanguine/services/rfq/relayer/relconfig"
    )
    
    func TestToAddressIsWhitelisted(t *testing.T) {
        cfg := relconfig.Config{
            WithdrawalWhitelist: []string{
                "0x1111111111111111111111111111111111111111",
                "0x2222222222222222222222222222222222222222",
            },
        }
    
        tests := []struct {
            name      string
            toAddress common.Address
            expected  bool
        }{
            {
                name:      "Address is whitelisted",
                toAddress: common.HexToAddress("0x1111111111111111111111111111111111111111"),
                expected:  true,
            },
            {
                name:      "Address is not whitelisted",
                toAddress: common.HexToAddress("0x3333333333333333333333333333333333333333"),
                expected:  false,
            },
        }
    
        for _, tt := range tests {
            t.Run(tt.name, func(t *testing.T) {
                result := relapi.ToAddressIsWhitelisted(cfg, tt.toAddress)
                assert.Equal(t, tt.expected, result)
            })
        }
    }

This approach ensures that the toAddressIsWhitelisted function is tested directly without the need to run the entire API.


Learnings added
Learnt from: trajan0x
PR: synapsecns/sanguine#2815
File: services/rfq/relayer/relapi/handler.go:162-165
Timestamp: 2024-07-02T14:49:46.333Z
Learning: When adding new validation logic in the `Withdraw` function, ensure to export helper functions like `toAddressIsWhitelisted` for direct unit testing.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


Learnings used
Learnt from: trajan0x
PR: synapsecns/sanguine#2815
File: services/rfq/relayer/relapi/handler.go:154-156
Timestamp: 2024-06-29T05:11:50.952Z
Learning: When adding new validation logic in the `Withdraw` function, ensure to cover it with unit tests to handle various scenarios.

Learnt from: trajan0x
PR: synapsecns/sanguine#2815
File: services/rfq/relayer/relapi/handler.go:153-156
Timestamp: 2024-06-29T05:12:50.268Z
Learning: When adding new validation logic in the `Withdraw` function, ensure to cover it with unit tests to handle various scenarios.

Learnt from: trajan0x
PR: synapsecns/sanguine#2815
File: services/rfq/relayer/relapi/handler.go:162-165
Timestamp: 2024-07-02T14:43:19.311Z
Learning: When adding new validation logic in the `Withdraw` function, ensure to cover it with unit tests to handle various scenarios, including valid and invalid addresses.

Learnt from: trajan0x
PR: synapsecns/sanguine#2815
File: services/rfq/relayer/relapi/handler.go:280-282
Timestamp: 2024-07-02T14:43:41.835Z
Learning: When the `UnmarshalJSON` method is added or modified in the `WithdrawRequest` struct, ensure to cover it with unit tests to handle various scenarios, including valid and invalid JSON inputs.

trajan0x marked this conversation as resolved.
Show resolved Hide resolved
trajan0x marked this conversation as resolved.
Show resolved Hide resolved

var nonce uint64
var err error

value, ok := new(big.Int).SetString(req.Amount, 10)
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("invalid amount %s", req.Amount)})
return
}

Check warning on line 171 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L169-L171

Added lines #L169 - L171 were not covered by tests
trajan0x marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +172 to +174
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for amount validation.

The validation of the amount in the Withdraw function is not covered by tests. Ensure that this validation is tested for various scenarios.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 168-170: services/rfq/relayer/relapi/handler.go#L168-L170
Added lines #L168 - L170 were not covered by tests

trajan0x marked this conversation as resolved.
Show resolved Hide resolved

if chain.IsGasToken(req.TokenAddress) {

Check failure on line 173 in services/rfq/relayer/relapi/handler.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

`if chain.IsGasToken(req.TokenAddress)` has complex nested blocks (complexity: 5) (nestif)
nonce, err = h.submitter.SubmitTransaction(c, big.NewInt(int64(req.ChainID)), func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) {
bc := bind.NewBoundContract(req.To, abi.ABI{}, h.chains[req.ChainID].Client, h.chains[req.ChainID].Client, h.chains[req.ChainID].Client)
if transactor.GasPrice != nil {
transactor.Value = value
// nolint: wrapcheck
return bc.Transfer(transactor)
}

return transactor.Signer(h.submitter.Address(), tx)

Check failure on line 182 in services/rfq/relayer/relapi/handler.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

error returned from external package is unwrapped: sig: field Signer github.com/ethereum/go-ethereum/accounts/abi/bind.SignerFn (wrapcheck)

Check warning on line 182 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L182

Added line #L182 was not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

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

Wrap error returned from external package.

The error returned from the external package should be wrapped to provide more context.

-	return transactor.Signer(h.submitter.Address(), tx)
+	return transactor.Signer(h.submitter.Address(), tx) //nolint: wrapcheck

Committable suggestion was skipped due to low confidence.

Tools
GitHub Check: Lint (services/rfq)

[failure] 181-181:
error returned from external package is unwrapped: sig: field Signer github.com/ethereum/go-ethereum/accounts/abi/bind.SignerFn (wrapcheck)

})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("could not submit transaction: %s", err.Error())})
return
}

Check warning on line 187 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L185-L187

Added lines #L185 - L187 were not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for gas token withdrawal.

The gas token withdrawal logic in the Withdraw function is not covered by tests. Ensure that this logic is tested for various scenarios.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 185-187: services/rfq/relayer/relapi/handler.go#L185-L187
Added lines #L185 - L187 were not covered by tests

GitHub Check: Lint (services/rfq)

[failure] 173-173:
if chain.IsGasToken(req.TokenAddress) has complex nested blocks (complexity: 5) (nestif)


[failure] 182-182:
error returned from external package is unwrapped: sig: field Signer github.com/ethereum/go-ethereum/accounts/abi/bind.SignerFn (wrapcheck)

} else {
erc20Contract, err := ierc20.NewIERC20(req.TokenAddress, h.chains[req.ChainID].Client)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("could not create erc20 contract: %s", err.Error())})
return
}

Check warning on line 193 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L191-L193

Added lines #L191 - L193 were not covered by tests
Comment on lines +192 to +200
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for gas token withdrawal.

The gas token withdrawal logic in the Withdraw function is not covered by tests. Ensure that this logic is tested for various scenarios.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 184-192: services/rfq/relayer/relapi/handler.go#L184-L192
Added lines #L184 - L192 were not covered by tests


nonce, err = h.submitter.SubmitTransaction(c, big.NewInt(int64(req.ChainID)), func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) {
// nolint: wrapcheck
return erc20Contract.Transfer(transactor, req.To, value)
trajan0x marked this conversation as resolved.
Show resolved Hide resolved
Copy link

Choose a reason for hiding this comment

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

🪶 style: Consider adding error handling for the erc20Contract.Transfer call.

Comment on lines +202 to +204
Copy link

Choose a reason for hiding this comment

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

🪶 style: Consider adding error handling for the erc20Contract.Transfer call.

})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("could not submit transaction: %s", err.Error())})
return
}

Check warning on line 202 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L200-L202

Added lines #L200 - L202 were not covered by tests
Comment on lines +202 to +209
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for ERC20 token withdrawal.

The ERC20 token withdrawal logic in the Withdraw function is not covered by tests. Ensure that this logic is tested for various scenarios.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 194-194: services/rfq/relayer/relapi/handler.go#L194
Added line #L194 was not covered by tests


[warning] 197-201: services/rfq/relayer/relapi/handler.go#L197-L201
Added lines #L197 - L201 were not covered by tests

Comment on lines +196 to +209
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for ERC20 token withdrawal.

The ERC20 token withdrawal logic in the Withdraw function is not covered by tests. Ensure that this logic is tested for various scenarios.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 191-193: services/rfq/relayer/relapi/handler.go#L191-L193
Added lines #L191 - L193 were not covered by tests


[warning] 200-202: services/rfq/relayer/relapi/handler.go#L200-L202
Added lines #L200 - L202 were not covered by tests

}

c.JSON(http.StatusOK, gin.H{"nonce": nonce})
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for successful withdrawal response.

The successful withdrawal response in the Withdraw function is not covered by tests. Ensure that this response is tested.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

}

// tokenIDExists checks if a token ID exists in the config.
// note: this method assumes that SanitizeTokenID is a method of relconfig.Config
func tokenIDExists(cfg relconfig.Config, tokenAddress common.Address, chainID int) bool {
for quotableToken := range cfg.QuotableTokens {
prospectiveChainID, prospectiveAddress, err := relconfig.DecodeTokenID(quotableToken)
if err != nil {
continue

Check warning on line 214 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L214

Added line #L214 was not covered by tests
Comment on lines +217 to +221
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for tokenIDExists function.

The tokenIDExists function is not covered by tests. Ensure that this function is tested for various scenarios.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 213-213: services/rfq/relayer/relapi/handler.go#L213
Added line #L213 was not covered by tests

}

if prospectiveChainID == chainID && prospectiveAddress == tokenAddress {
return true
}
}

return false

Check warning on line 222 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L222

Added line #L222 was not covered by tests
}
Comment on lines +215 to +230
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for tokenIDExists function.

Ensure that this function is tested for various scenarios, such as valid token addresses, invalid token addresses, and edge cases.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?


func toAddressIsWhitelisted(cfg relconfig.Config, to common.Address) bool {
for _, addr := range cfg.WithdrawalWhitelist {
if common.HexToAddress(addr) == to {
return true
}
Comment on lines +232 to +236
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for toAddressIsWhitelisted function.

The toAddressIsWhitelisted function is not covered by tests. Ensure that this function is tested for various scenarios.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

}
return false

Check warning on line 231 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L231

Added line #L231 was not covered by tests
}
Comment on lines +232 to +239
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for toAddressIsWhitelisted function.

Ensure that this function is tested for various scenarios, such as valid addresses, invalid addresses, and edge cases.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?


// WithdrawRequest is the request to withdraw tokens from the relayer.
type WithdrawRequest struct {
// ChainID is the chain ID of the chain to withdraw from.
ChainID uint32 `json:"chain_id"`
// Amount is the amount to withdraw, in wei.
Amount string `json:"amount"`
// TokenAddress is the address of the token to withdraw.
TokenAddress common.Address `json:"token_address"`
// To is the address to withdraw to.
To common.Address `json:"to"`
}

// MarshalJSON handles JSON marshaling for WithdrawRequest.
func (wr *WithdrawRequest) MarshalJSON() ([]byte, error) {
type Alias WithdrawRequest
// nolint: wrapcheck
return json.Marshal(&struct {
TokenAddress string `json:"token_address"`
To string `json:"to"`
*Alias
}{
TokenAddress: wr.TokenAddress.Hex(),
To: wr.To.Hex(),
Alias: (*Alias)(wr),
})
trajan0x marked this conversation as resolved.
Show resolved Hide resolved
}
Comment on lines +241 to +266
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for MarshalJSON method.

The MarshalJSON method in the WithdrawRequest struct is not covered by tests. Ensure that this method is tested for various scenarios.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?


// UnmarshalJSON has JSON unmarshalling for WithdrawRequest.
func (wr *WithdrawRequest) UnmarshalJSON(data []byte) error {
type Alias WithdrawRequest
aux := &struct {
TokenAddress string `json:"token_address"`
To string `json:"to"`
*Alias
}{
Alias: (*Alias)(wr),
}

if err := json.Unmarshal(data, aux); err != nil {
//nolint: wrapcheck
return err
}

Check warning on line 275 in services/rfq/relayer/relapi/handler.go

View check run for this annotation

Codecov / codecov/patch

services/rfq/relayer/relapi/handler.go#L273-L275

Added lines #L273 - L275 were not covered by tests
trajan0x marked this conversation as resolved.
Show resolved Hide resolved

wr.TokenAddress = common.HexToAddress(aux.TokenAddress)
wr.To = common.HexToAddress(aux.To)

return nil
}
Comment on lines +268 to +288
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for UnmarshalJSON method.

Ensure that this method is tested for various scenarios, such as valid JSON inputs, invalid JSON inputs, and edge cases.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

34 changes: 34 additions & 0 deletions services/rfq/relayer/relapi/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package relapi_test

import (
"encoding/json"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/synapsecns/sanguine/services/rfq/relayer/relapi"
"testing"
)

func TestWithdrawRequestJSON(t *testing.T) {
original := relapi.WithdrawRequest{
ChainID: 1,
Amount: "100",
TokenAddress: common.HexToAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"),
To: common.HexToAddress("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"),
}

// Marshal to JSON
data, err := json.Marshal(original)
assert.NoError(t, err)

// Unmarshal back to struct
var unmarshalled relapi.WithdrawRequest
err = json.Unmarshal(data, &unmarshalled)
assert.NoError(t, err)

// Check if the original and unmarshalled structs are the same
assert.Equal(t, original, unmarshalled)

// Check the JSON string explicitly
expectedJSON := `{"chain_id":1,"amount":"100","token_address":"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee","to":"0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"}`
assert.JSONEq(t, expectedJSON, string(data))
}
30 changes: 19 additions & 11 deletions services/rfq/relayer/relapi/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ import (
// RelayerAPIServer 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 RelayerAPIServer struct {
cfg relconfig.Config
db reldb.Service
engine *gin.Engine
handler metrics.Handler
chains map[uint32]*chain.Chain
cfg relconfig.Config
db reldb.Service
engine *gin.Engine
handler metrics.Handler
chains map[uint32]*chain.Chain
submitter submitter.TransactionSubmitter
}

// NewRelayerAPI holds the configuration, database connection, gin engine, RPC client, metrics handler, and fast bridge contracts.
Expand Down Expand Up @@ -86,10 +87,11 @@ func NewRelayerAPI(
}

return &RelayerAPIServer{
cfg: cfg,
db: store,
handler: handler,
chains: chains,
cfg: cfg,
db: store,
handler: handler,
chains: chains,
submitter: submitter,
}, nil
}

Expand All @@ -98,15 +100,17 @@ const (
getQuoteStatusByTxHashRoute = "/status"
getQuoteStatusByTxIDRoute = "/status/by_tx_id"
getRetryRoute = "/retry"
postWithdrawRoute = "/withdraw"
)

var logger = log.Logger("relayer-api")

// Run runs the rest api server.
func (r *RelayerAPIServer) Run(ctx context.Context) error {
// TODO: Use Gin Helper
engine := ginhelper.New(logger)
h := NewHandler(r.db, r.chains)
// default tracing middleware
engine.Use(r.handler.Gin()...)
h := NewHandler(r.db, r.chains, r.cfg, r.submitter)

// Assign GET routes
engine.GET(getHealthRoute, h.GetHealth)
Expand All @@ -115,6 +119,10 @@ func (r *RelayerAPIServer) Run(ctx context.Context) error {
engine.GET(getRetryRoute, h.GetTxRetry)
engine.GET(metrics.MetricsPathDefault, gin.WrapH(r.handler.Handler()))

if r.cfg.EnableAPIWithdrawals {
engine.POST(postWithdrawRoute, h.Withdraw)
}
Comment on lines +122 to +124
Copy link
Contributor

Choose a reason for hiding this comment

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

Add tests for the withdrawal route.

The POST /withdraw route is only added if EnableAPIWithdrawals is true. Ensure that this route is covered by tests.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

Tools
GitHub Check: codecov/patch

[warning] 123-124: services/rfq/relayer/relapi/server.go#L123-L124
Added lines #L123 - L124 were not covered by tests


r.engine = engine

connection := baseServer.Server{}
Expand Down
Loading
Loading