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

FE Release 2024-11-11 #3385

Merged
merged 11 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
56 changes: 45 additions & 11 deletions contrib/opbot/botmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package botmd

import (
"context"
"errors"
"fmt"
"log"
"math/big"
Expand All @@ -20,8 +19,8 @@ import (
"github.com/hako/durafmt"
"github.com/slack-go/slack"
"github.com/slack-io/slacker"
"github.com/synapsecns/sanguine/contrib/opbot/internal"
"github.com/synapsecns/sanguine/contrib/opbot/signoz"
"github.com/synapsecns/sanguine/core"
"github.com/synapsecns/sanguine/core/retry"
"github.com/synapsecns/sanguine/ethergo/chaindata"
"github.com/synapsecns/sanguine/ethergo/submitter"
Expand Down Expand Up @@ -250,7 +249,8 @@ func (b *Bot) rfqRefund() *slacker.CommandDefinition {
return
}

fastBridgeContract, err := b.makeFastBridge(ctx.Context(), rawRequest)
//nolint: gosec
fastBridgeContractOrigin, err := b.makeFastBridge(ctx.Context(), uint32(rawRequest.Bridge.OriginChainID))
Comment on lines +252 to +253
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid suppressing gosec linter warnings without justification.

Using //nolint: gosec suppresses potential security issues flagged by the linter. It's advisable to address the underlying security concerns or, if suppression is necessary, provide a justification comment explaining why.

if err != nil {
_, err := ctx.Response().Reply(err.Error())
if err != nil {
Expand All @@ -275,11 +275,44 @@ func (b *Bot) rfqRefund() *slacker.CommandDefinition {
return
}

//nolint:gosec
fastBridgeContractDest, err := b.makeFastBridge(ctx.Context(), uint32(rawRequest.Bridge.DestChainID))
if err != nil {
_, err := ctx.Response().Reply(err.Error())
if err != nil {
log.Println(err)
}
return
}
txBz, err := core.BytesToArray(common.Hex2Bytes(rawRequest.Bridge.TransactionID[2:]))
if err != nil {
_, err := ctx.Response().Reply("error converting tx id")
if err != nil {
log.Println(err)
}
return
}
Comment on lines +287 to +294
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use common.FromHex to safely decode hexadecimal strings and avoid manual slicing.

Instead of manually removing the "0x" prefix and using common.Hex2Bytes, it's safer and more idiomatic to use common.FromHex, which handles the prefix automatically and returns an error for invalid input. This prevents potential runtime panics due to incorrect slicing.

Apply this diff to update the code:

-	txBz, err := core.BytesToArray(common.Hex2Bytes(rawRequest.Bridge.TransactionID[2:]))
+	txBytes, err := common.FromHex(rawRequest.Bridge.TransactionID)
+	if err != nil {
+		_, err := ctx.Response().Reply("error converting tx id")
+		if err != nil {
+			log.Println(err)
+		}
+		return
+	}
+	txBz, err := core.BytesToArray(txBytes)
	if err != nil {
		_, err := ctx.Response().Reply("error converting tx bytes")
		if err != nil {
			log.Println(err)
		}
		return
	}
📝 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
txBz, err := core.BytesToArray(common.Hex2Bytes(rawRequest.Bridge.TransactionID[2:]))
if err != nil {
_, err := ctx.Response().Reply("error converting tx id")
if err != nil {
log.Println(err)
}
return
}
txBytes, err := common.FromHex(rawRequest.Bridge.TransactionID)
if err != nil {
_, err := ctx.Response().Reply("error converting tx id")
if err != nil {
log.Println(err)
}
return
}
txBz, err := core.BytesToArray(txBytes)
if err != nil {
_, err := ctx.Response().Reply("error converting tx bytes")
if err != nil {
log.Println(err)
}
return
}

isRelayed, err := fastBridgeContractDest.BridgeRelays(nil, txBz)
if err != nil {
_, err := ctx.Response().Reply("error fetching bridge relays")
if err != nil {
log.Println(err)
}
return
}
if isRelayed {
_, err := ctx.Response().Reply("transaction has already been relayed")
if err != nil {
log.Println(err)
}
return
}

nonce, err := b.submitter.SubmitTransaction(
ctx.Context(),
big.NewInt(int64(rawRequest.Bridge.OriginChainID)),
func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) {
tx, err = fastBridgeContract.Refund(transactor, common.Hex2Bytes(rawRequest.Bridge.Request[2:]))
tx, err = fastBridgeContractOrigin.Refund(transactor, common.Hex2Bytes(rawRequest.Bridge.Request[2:]))
if err != nil {
return nil, fmt.Errorf("error submitting refund: %w", err)
Comment on lines +315 to 317
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use common.FromHex for safer hexadecimal decoding of the bridge request.

Consistent with earlier, utilizing common.FromHex enhances safety by automatically handling the "0x" prefix and error checking, reducing the risk of runtime issues.

Apply this diff to update the code:

-	tx, err = fastBridgeContractOrigin.Refund(transactor, common.Hex2Bytes(rawRequest.Bridge.Request[2:]))
+	requestBytes, err := common.FromHex(rawRequest.Bridge.Request)
+	if err != nil {
+		return nil, fmt.Errorf("error decoding bridge request: %w", err)
+	}
+	tx, err = fastBridgeContractOrigin.Refund(transactor, requestBytes)
	if err != nil {
		return nil, fmt.Errorf("error submitting refund: %w", err)
	}
	return tx, nil
📝 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
tx, err = fastBridgeContractOrigin.Refund(transactor, common.Hex2Bytes(rawRequest.Bridge.Request[2:]))
if err != nil {
return nil, fmt.Errorf("error submitting refund: %w", err)
requestBytes, err := common.FromHex(rawRequest.Bridge.Request)
if err != nil {
return nil, fmt.Errorf("error decoding bridge request: %w", err)
}
tx, err = fastBridgeContractOrigin.Refund(transactor, requestBytes)
if err != nil {
return nil, fmt.Errorf("error submitting refund: %w", err)
}
return tx, nil

}
Expand Down Expand Up @@ -322,7 +355,7 @@ func (b *Bot) rfqRefund() *slacker.CommandDefinition {
}
}

func (b *Bot) makeFastBridge(ctx context.Context, req *internal.GetRFQByTxIDResponse) (*fastbridge.FastBridge, error) {
func (b *Bot) makeFastBridge(ctx context.Context, chainID uint32) (*fastbridge.FastBridge, error) {
client, err := rfqClient.NewUnauthenticatedClient(b.handler, b.cfg.RFQApiURL)
if err != nil {
return nil, fmt.Errorf("error creating rfq client: %w", err)
Expand All @@ -333,22 +366,23 @@ func (b *Bot) makeFastBridge(ctx context.Context, req *internal.GetRFQByTxIDResp
return nil, fmt.Errorf("error fetching rfq contracts: %w", err)
}

chainClient, err := b.rpcClient.GetChainClient(ctx, req.Bridge.OriginChainID)
chainClient, err := b.rpcClient.GetChainClient(ctx, int(chainID))
if err != nil {
return nil, fmt.Errorf("error getting chain client: %w", err)
return nil, fmt.Errorf("error getting chain client for chain ID %d: %w", chainID, err)
}

//nolint: gosec
contractAddress, ok := contracts.Contracts[uint32(req.Bridge.OriginChainID)]
contractAddress, ok := contracts.Contracts[chainID]
if !ok {
return nil, errors.New("contract address not found")
return nil, fmt.Errorf("no contract address for chain ID")
}

fastBridgeHandle, err := fastbridge.NewFastBridge(common.HexToAddress(contractAddress), chainClient)
if err != nil {
return nil, fmt.Errorf("error creating fast bridge: %w", err)
return nil, fmt.Errorf("error creating fast bridge for chain ID %d: %w", chainID, err)
}

return fastBridgeHandle, nil

}

func toExplorerSlackLink(ogHash string) string {
Expand Down
10 changes: 10 additions & 0 deletions core/bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,13 @@ func BytesToJSONString(bz []byte) (string, error) {

return string(formattedJSON), nil
}

// BytesToArray converts a slice to a 32 length byte array.
func BytesToArray(bz []byte) ([32]byte, error) {
var bytes [32]byte
if len(bz) != 32 {
return bytes, fmt.Errorf("invalid length of bytes: %d", len(bz))
}
copy(bytes[:], bz)
return bytes, nil
}
Comment on lines +30 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.

💡 Codebase verification

Add unit tests for BytesToArray function

The BytesToArray function currently lacks test coverage. Please add test cases to verify:

  • Success case with valid 32-byte input
  • Error case with input length ≠ 32 bytes

Example test cases should include:

  • Valid 32-byte array conversion
  • Input shorter than 32 bytes
  • Input longer than 32 bytes
🔗 Analysis chain

Add unit tests to verify error handling.

The new function includes error handling that should be verified with tests, especially the case where input length ≠ 32 bytes.

Let's check if tests exist:

Would you like me to help generate comprehensive test cases for this function?

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for existing tests of BytesToArray function
# Expected: Find test file and verify coverage of error case

# Look for test file
echo "Searching for test file..."
fd "bytes_test.go" core/

# Check for error case testing
echo "Checking for error case testing..."
rg -A 5 "TestBytesToArray.*func" core/

Length of output: 226


Script:

#!/bin/bash
# Let's check the content of the test file to verify test coverage
cat core/bytes_test.go

Length of output: 2405

8 changes: 8 additions & 0 deletions packages/contracts-rfq/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [0.12.1](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.12.0...@synapsecns/contracts-rfq@0.12.1) (2024-11-11)

**Note:** Version bump only for package @synapsecns/contracts-rfq





# [0.12.0](https://github.com/synapsecns/sanguine/compare/@synapsecns/contracts-rfq@0.11.0...@synapsecns/contracts-rfq@0.12.0) (2024-11-04)


Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/contracts/interfaces/IAdmin.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;

interface IAdmin {
// ============ Events ============
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;

interface IFastBridge {
struct BridgeTransaction {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;

import {IFastBridge} from "./IFastBridge.sol";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;

interface IFastBridgeV2Errors {
error AmountIncorrect();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;

/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:
/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;

interface IZapRecipient {
function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;
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

Pragma version downgrade introduces compatibility issues with dependent contract

The pragma version downgrade to ^0.8.4 in BridgeTransactionV2.sol creates a version mismatch with its main dependent contract FastBridgeV2.sol (which uses 0.8.24). This could lead to potential compilation issues since the library is used directly in FastBridgeV2 with the statement using BridgeTransactionV2Lib for bytes.

  • FastBridgeV2.sol (0.8.24) imports and uses BridgeTransactionV2 library (^0.8.4)
  • The only other dependency is IFastBridgeV2.sol which is already compatible with ^0.8.4

Consider either:

  • Upgrading BridgeTransactionV2.sol to match FastBridgeV2.sol's version (0.8.24)
  • Or downgrading FastBridgeV2.sol to maintain version alignment
🔗 Analysis chain

Verify compiler version compatibility across dependencies

While downgrading from ^0.8.20 to ^0.8.4 aligns with other contracts, ensure all dependencies and inherited contracts are compatible with this version range.

Consider documenting the rationale for this version alignment in the repository's documentation to help future maintainers understand the decision.


The previous results show varying pragma versions across the codebase, with some contracts using newer versions (0.8.24, 0.8.20) and others using older versions (0.8.4, 0.8.17). Let's verify the dependencies and usage of BridgeTransactionV2 to ensure version compatibility.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check pragma versions across related contracts
echo "Checking pragma versions in related contracts..."
rg -A 1 "pragma solidity" "packages/contracts-rfq/contracts/"

# Check if any newer Solidity features are used
echo "Checking for newer Solidity features usage..."
rg -i "push\s*\[\s*\]|assembly\s*\{\s*basefee|block\.prevrandao|PUSH0" "packages/contracts-rfq/contracts/"

Length of output: 4493


Script:

#!/bin/bash
# Check for imports and dependencies of BridgeTransactionV2.sol
echo "Checking imports in BridgeTransactionV2.sol..."
rg "^import.*;" "packages/contracts-rfq/contracts/libs/BridgeTransactionV2.sol"

# Check which contracts import BridgeTransactionV2
echo "Checking usage of BridgeTransactionV2..."
rg "import.*BridgeTransactionV2" "packages/contracts-rfq/contracts/"

# Check if there are any inheritance or library usage
echo "Checking for library usage of BridgeTransactionV2..."
rg "using BridgeTransactionV2" "packages/contracts-rfq/contracts/"

Length of output: 802


import {IFastBridgeV2} from "../interfaces/IFastBridgeV2.sol";

Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/contracts/libs/Errors.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;

error DeadlineExceeded();
error DeadlineNotExceeded();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity ^0.8.4;

import {IMulticallTarget} from "../interfaces/IMulticallTarget.sol";

Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@synapsecns/contracts-rfq",
"license": "MIT",
"version": "0.12.0",
"version": "0.12.1",
"description": "FastBridge contracts.",
"private": true,
"files": [
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/test/MulticallTarget.t.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

import {IMulticallTarget} from "../contracts/interfaces/IMulticallTarget.sol";
import {MulticallTargetHarness, MulticallTarget} from "./harnesses/MulticallTargetHarness.sol";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

import {MulticallTarget} from "../../contracts/utils/MulticallTarget.sol";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

import {IZapRecipient} from "../../contracts/interfaces/IZapRecipient.sol";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

import {IZapRecipient} from "../../contracts/interfaces/IZapRecipient.sol";

Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/test/mocks/NoOpContract.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

// solhint-disable-next-line no-empty-blocks
contract NoOpContract {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

// solhint-disable no-empty-blocks
/// @notice Incorrectly implemented recipient mock for testing purposes. DO NOT USE IN PRODUCTION.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

// solhint-disable no-empty-blocks
/// @notice Incorrectly implemented recipient mock for testing purposes. DO NOT USE IN PRODUCTION.
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/test/mocks/RecipientMock.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

import {IZapRecipient} from "../../contracts/interfaces/IZapRecipient.sol";

Expand Down
24 changes: 24 additions & 0 deletions packages/rest-api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [1.8.7](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.8.6...@synapsecns/rest-api@1.8.7) (2024-11-11)

**Note:** Version bump only for package @synapsecns/rest-api





## [1.8.6](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.8.5...@synapsecns/rest-api@1.8.6) (2024-11-07)

**Note:** Version bump only for package @synapsecns/rest-api





## [1.8.5](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.8.4...@synapsecns/rest-api@1.8.5) (2024-11-07)

**Note:** Version bump only for package @synapsecns/rest-api





## [1.8.4](https://github.com/synapsecns/sanguine/compare/@synapsecns/rest-api@1.8.3...@synapsecns/rest-api@1.8.4) (2024-11-01)

**Note:** Version bump only for package @synapsecns/rest-api
Expand Down
4 changes: 2 additions & 2 deletions packages/rest-api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@synapsecns/rest-api",
"version": "1.8.4",
"version": "1.8.7",
"private": "true",
"engines": {
"node": ">=18.17.0"
Expand All @@ -22,7 +22,7 @@
"@ethersproject/bignumber": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
"@ethersproject/units": "5.7.0",
"@synapsecns/sdk-router": "^0.11.5",
"@synapsecns/sdk-router": "^0.11.6",
"bignumber": "^1.1.0",
"dotenv": "^16.4.5",
"ethers": "5.7.2",
Expand Down
13 changes: 13 additions & 0 deletions packages/rest-api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ import {
const app = express()
const port = process.env.PORT || 3000

app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*')
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS')
res.setHeader('Access-Control-Allow-Headers', '*')

if (req.method === 'OPTIONS') {
res.sendStatus(200)
return
}

next()
})

app.use(express.json())

app.use((req, res, next) => {
Expand Down
18 changes: 16 additions & 2 deletions packages/rest-api/src/routes/bridgeRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { isTokenSupportedOnChain } from '../utils/isTokenSupportedOnChain'
import { checksumAddresses } from '../middleware/checksumAddresses'
import { normalizeNativeTokenAddress } from '../middleware/normalizeNativeTokenAddress'
import { validateRouteExists } from '../validations/validateRouteExists'

import { validateDecimals } from '../validations/validateDecimals'
import { tokenAddressToToken } from '../utils/tokenAddressToToken'
const router: express.Router = express.Router()

/**
Expand Down Expand Up @@ -227,7 +228,20 @@ router.get(
isTokenSupportedOnChain(value, req.query.toChain as string)
)
.withMessage('Token not supported on specified chain'),
check('amount').isNumeric().exists().withMessage('amount is required'),
check('amount')
.exists()
.withMessage('amount is required')
.isNumeric()
.custom((value, { req }) => {
const fromTokenInfo = tokenAddressToToken(
req.query.fromChain,
req.query.fromToken
)
return validateDecimals(value, fromTokenInfo.decimals)
})
.withMessage(
'Amount has too many decimals, beyond the maximum allowed for this token'
),
Comment on lines +231 to +244
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance error handling and performance of amount validation

While the decimal validation is a good addition, there are a few areas for improvement:

  1. Error Handling: Add explicit error handling for tokenAddressToToken failures
  2. Performance: Consider caching token info to avoid repeated lookups
  3. Input Validation: Consider adding range checks for amount

Consider this improved implementation:

 check('amount')
   .exists()
   .withMessage('amount is required')
   .isNumeric()
+  .isFloat({ min: 0 })
+  .withMessage('Amount must be greater than 0')
   .custom((value, { req }) => {
+    try {
       const fromTokenInfo = tokenAddressToToken(
         req.query.fromChain,
         req.query.fromToken
       )
+      if (!fromTokenInfo) {
+        throw new Error('Token information not found')
+      }
       return validateDecimals(value, fromTokenInfo.decimals)
+    } catch (error) {
+      throw new Error(`Invalid amount: ${error.message}`)
+    }
   })
   .withMessage(
     'Amount has too many decimals, beyond the maximum allowed for this token'
   ),
📝 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
check('amount')
.exists()
.withMessage('amount is required')
.isNumeric()
.custom((value, { req }) => {
const fromTokenInfo = tokenAddressToToken(
req.query.fromChain,
req.query.fromToken
)
return validateDecimals(value, fromTokenInfo.decimals)
})
.withMessage(
'Amount has too many decimals, beyond the maximum allowed for this token'
),
check('amount')
.exists()
.withMessage('amount is required')
.isNumeric()
.isFloat({ min: 0 })
.withMessage('Amount must be greater than 0')
.custom((value, { req }) => {
try {
const fromTokenInfo = tokenAddressToToken(
req.query.fromChain,
req.query.fromToken
)
if (!fromTokenInfo) {
throw new Error('Token information not found')
}
return validateDecimals(value, fromTokenInfo.decimals)
} catch (error) {
throw new Error(`Invalid amount: ${error.message}`)
}
})
.withMessage(
'Amount has too many decimals, beyond the maximum allowed for this token'
),

check()
.custom((_value, { req }) => {
const { fromChain, toChain, fromToken, toToken } = req.query
Expand Down
Loading
Loading