-
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
2024-09-26 FE Release #3155
2024-09-26 FE Release #3155
Changes from 9 commits
89907ce
b07d94e
6e41b29
9049299
7a118c9
0b64779
d4d1c5a
bf22448
5052439
a03677e
4ed82b0
1b821a0
965736b
fd1540d
8e12c27
4f4c201
b1eca8a
86415c0
49cf94d
01ec2d4
8127a4c
d7599c3
c262b01
c32b70b
ce1defe
304ecda
fd0aecb
23f6c4c
dd67210
4a0f2e7
1eb52a0
3b507bd
f4101f2
4cb5d73
1891fed
4680ddc
faf9387
8c702c7
9418b40
1eb6fa0
6f21b1a
1de17e0
b6651b1
0daec70
74b620e
038605d
98362bb
67a04cd
c15ec86
11ac650
8113d0b
e89b363
7594100
6ec996d
ceff8bc
3af3438
3e75b0d
2e808e6
1bdfee6
2709e85
9742f8f
abeea4d
fc6ddae
90ac800
fe71628
5c8a069
65ee496
1c5e21d
4a45bcf
d8338fe
f0b13bc
96bf50f
e897b18
ebf102c
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 |
---|---|---|
|
@@ -3,6 +3,22 @@ | |
All notable changes to this project will be documented in this file. | ||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. | ||
|
||
## [1.0.76](https://github.com/synapsecns/sanguine/compare/@synapsecns/[email protected]...@synapsecns/[email protected]) (2024-09-19) | ||
|
||
**Note:** Version bump only for package @synapsecns/rest-api | ||
|
||
|
||
|
||
|
||
|
||
## [1.0.75](https://github.com/synapsecns/sanguine/compare/@synapsecns/[email protected]...@synapsecns/[email protected]) (2024-09-18) | ||
|
||
**Note:** Version bump only for package @synapsecns/rest-api | ||
|
||
|
||
|
||
|
||
|
||
## [1.0.74](https://github.com/synapsecns/sanguine/compare/@synapsecns/[email protected]...@synapsecns/[email protected]) (2024-09-16) | ||
|
||
**Note:** Version bump only for package @synapsecns/rest-api | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { validationResult } from 'express-validator' | ||
|
||
import { tokenAddressToToken } from '../utils/tokenAddressToToken' | ||
import { BRIDGE_ROUTE_MAPPING } from '../utils/bridgeRouteMapping' | ||
|
||
export const destinationTokensController = async (req, res) => { | ||
const errors = validationResult(req) | ||
if (!errors.isEmpty()) { | ||
return res.status(400).json({ errors: errors.array() }) | ||
} | ||
|
||
try { | ||
const { fromChain, fromToken } = req.query | ||
|
||
const fromTokenInfo = tokenAddressToToken(fromChain.toString(), fromToken) | ||
|
||
const constructedKey = `${fromTokenInfo.symbol}-${fromChain}` | ||
|
||
const options = BRIDGE_ROUTE_MAPPING[constructedKey] | ||
|
||
res.json(options) | ||
} catch (err) { | ||
res.status(500).json({ | ||
error: | ||
'An unexpected error occurred in /destinationTokens. Please try again later.', | ||
details: err.message, | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,37 @@ | ||
import { validationResult } from 'express-validator' | ||
import { formatUnits, parseUnits } from '@ethersproject/units' | ||
import { BigNumber } from '@ethersproject/bignumber' | ||
|
||
import { Synapse } from '../services/synapseService' | ||
import { tokenAddressToToken } from '../utils/tokenAddressToToken' | ||
|
||
export const swapController = async (req, res) => { | ||
const errors = validationResult(req) | ||
if (!errors.isEmpty()) { | ||
return res.status(400).json({ errors: errors.array() }) | ||
} | ||
try { | ||
const { chain, amount } = req.query | ||
const fromTokenInfo = res.locals.tokenInfo.fromToken | ||
const toTokenInfo = res.locals.tokenInfo.toToken | ||
const { chain, amount, fromToken, toToken } = req.query | ||
|
||
const fromTokenInfo = tokenAddressToToken(chain.toString(), fromToken) | ||
const toTokenInfo = tokenAddressToToken(chain.toString(), toToken) | ||
|
||
const amountInWei = parseUnits(amount.toString(), fromTokenInfo.decimals) | ||
const quote = await Synapse.swapQuote( | ||
Number(chain), | ||
fromTokenInfo.address, | ||
toTokenInfo.address, | ||
fromToken, | ||
toToken, | ||
Comment on lines
+22
to
+23
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. Tip Codebase Verification Implement token address validation before using in swapQuote The review of To ensure the integrity of the swap operation and prevent potential errors or unexpected behavior, please implement the following:
const isValidEthereumAddress = (address) => /^0x[a-fA-F0-9]{40}$/.test(address);
if (!isValidEthereumAddress(fromToken) || !isValidEthereumAddress(toToken)) {
return res.status(400).json({ error: 'Invalid token address format.' });
}
This addition will help prevent potential issues caused by invalid token addresses and improve the overall robustness of the swap controller. Analysis chainValidate token addresses before calling Passing invalid Possible action: Implement validation logic for +const isValidAddress = (address) => /^0x[a-fA-F0-9]{40}$/.test(address);
+if (!isValidAddress(fromToken) || !isValidAddress(toToken)) {
+ return res.status(400).json({ error: 'Invalid token address format.' })
+}
const quote = await Synapse.swapQuote(
Number(chain),
fromToken,
toToken,
amountInWei
) Verification script: Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Verify that all token addresses conform to Ethereum address format.
# Test: Check if fromToken and toToken are valid hex addresses. Expect: Addresses match the regex pattern.
rg --type javascript --pattern '\bfromToken\b|\btoToken\b' -A 2
Length of output: 477 Script: #!/bin/bash
# Search for fromToken and toToken usage
rg '\b(fromToken|toToken)\b' -t js -A 2 -B 2
# Search for potential address validation functions
rg '(isValidAddress|validateAddress|checkAddress)' -t js
# Search for Ethereum address regex patterns
rg '0x[a-fA-F0-9]{40}' -t js
Length of output: 1234 Script: #!/bin/bash
# Check if the swapController.ts file exists
fd swapController.ts
# If the file exists, display its content
fd swapController.ts -x cat {}
# Search for fromToken and toToken usage in swapController.ts
fd swapController.ts -x rg '\b(fromToken|toToken)\b' {}
Length of output: 1664 |
||
amountInWei | ||
) | ||
|
||
const formattedMaxAmountOut = formatUnits( | ||
BigNumber.from(quote.maxAmountOut), | ||
toTokenInfo.decimals | ||
) | ||
|
||
Comment on lines
+27
to
+31
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. Ensure If Possible action: Add a validation step to confirm const formattedMaxAmountOut = formatUnits(
- BigNumber.from(quote.maxAmountOut),
+ BigNumber.from(quote.maxAmountOut || '0'),
toTokenInfo.decimals
) Or handle the case explicitly: +if (!quote.maxAmountOut) {
+ return res.status(500).json({ error: 'Failed to retrieve maxAmountOut from quote.' })
+}
const formattedMaxAmountOut = formatUnits(
BigNumber.from(quote.maxAmountOut),
toTokenInfo.decimals
)
|
||
res.json({ | ||
maxAmountOut: formatUnits(quote.maxAmountOut, toTokenInfo.decimals), | ||
...quote, | ||
maxAmountOut: formattedMaxAmountOut, | ||
}) | ||
} catch (err) { | ||
res.status(500).json({ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ import { validationResult } from 'express-validator' | |
import { parseUnits } from '@ethersproject/units' | ||
|
||
import { Synapse } from '../services/synapseService' | ||
import { tokenAddressToToken } from '../utils/tokenAddressToToken' | ||
|
||
export const swapTxInfoController = async (req, res) => { | ||
const errors = validationResult(req) | ||
|
@@ -10,23 +11,23 @@ export const swapTxInfoController = async (req, res) => { | |
} | ||
|
||
try { | ||
const { chain, amount } = req.query | ||
const fromTokenInfo = res.locals.tokenInfo.fromToken | ||
const toTokenInfo = res.locals.tokenInfo.toToken | ||
const { chain, amount, address, fromToken, toToken } = req.query | ||
|
||
const fromTokenInfo = tokenAddressToToken(chain.toString(), fromToken) | ||
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. Handle Potential Undefined 'fromTokenInfo' The Apply this diff to handle the undefined case: const fromTokenInfo = tokenAddressToToken(chain.toString(), fromToken)
+if (!fromTokenInfo) {
+ return res.status(400).json({ error: 'Invalid fromToken address' })
+}
const amountInWei = parseUnits(amount.toString(), fromTokenInfo.decimals)
|
||
|
||
const amountInWei = parseUnits(amount.toString(), fromTokenInfo.decimals) | ||
|
||
const quote = await Synapse.swapQuote( | ||
Number(chain), | ||
fromTokenInfo.address, | ||
toTokenInfo.address, | ||
fromToken, | ||
toToken, | ||
amountInWei | ||
) | ||
|
||
const txInfo = await Synapse.swap( | ||
Number(chain), | ||
fromTokenInfo.address, | ||
toTokenInfo.address, | ||
address, | ||
fromToken, | ||
amountInWei, | ||
quote.query | ||
) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { Request, Response, NextFunction } from 'express' | ||
import { getAddress, isAddress } from 'ethers/lib/utils' | ||
|
||
export const checksumAddresses = (addressFields: string[]) => { | ||
return (req: Request, _res: Response, next: NextFunction) => { | ||
for (const field of addressFields) { | ||
const address = req.query[field] | ||
if (typeof address === 'string' && isAddress(address)) { | ||
req.query[field] = getAddress(address) | ||
} | ||
} | ||
next() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,15 +1,18 @@ | ||||||||||||
import express from 'express' | ||||||||||||
import { check } from 'express-validator' | ||||||||||||
|
||||||||||||
import { isTokenAddress } from '../utils/isTokenAddress' | ||||||||||||
import { CHAINS_ARRAY } from '../constants/chains' | ||||||||||||
import { validateTokens } from '../validations/validateTokens' | ||||||||||||
import { showFirstValidationError } from '../middleware/showFirstValidationError' | ||||||||||||
import { bridgeController } from '../controllers/bridgeController' | ||||||||||||
import { isTokenSupportedOnChain } from '../utils/isTokenSupportedOnChain' | ||||||||||||
import { checksumAddresses } from '../middleware/checksumAddresses' | ||||||||||||
|
||||||||||||
const router = express.Router() | ||||||||||||
|
||||||||||||
router.get( | ||||||||||||
'/', | ||||||||||||
checksumAddresses(['fromToken', 'toToken']), | ||||||||||||
[ | ||||||||||||
check('fromChain') | ||||||||||||
.isNumeric() | ||||||||||||
|
@@ -23,9 +26,25 @@ router.get( | |||||||||||
.withMessage('Unsupported toChain') | ||||||||||||
.exists() | ||||||||||||
.withMessage('toChain is required'), | ||||||||||||
validateTokens('fromChain', 'fromToken', 'fromToken'), | ||||||||||||
validateTokens('toChain', 'toToken', 'toToken'), | ||||||||||||
check('amount').isNumeric(), | ||||||||||||
check('fromToken') | ||||||||||||
.exists() | ||||||||||||
.withMessage('fromToken is required') | ||||||||||||
.custom((value) => isTokenAddress(value)) | ||||||||||||
.withMessage('Invalid fromToken address') | ||||||||||||
.custom((value, { req }) => | ||||||||||||
isTokenSupportedOnChain(value, req.query.fromChain as string) | ||||||||||||
) | ||||||||||||
.withMessage('Token not supported on specified chain'), | ||||||||||||
check('toToken') | ||||||||||||
.exists() | ||||||||||||
.withMessage('toToken is required') | ||||||||||||
.custom((value) => isTokenAddress(value)) | ||||||||||||
.withMessage('Invalid toToken address') | ||||||||||||
.custom((value, { req }) => | ||||||||||||
isTokenSupportedOnChain(value, req.query.toChain as string) | ||||||||||||
) | ||||||||||||
.withMessage('Token not supported on specified chain'), | ||||||||||||
check('amount').isNumeric().exists().withMessage('amount is required'), | ||||||||||||
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. Swap the order of validators for the In the validation for the Apply this diff to correct the validator order: check('amount')
+ .exists()
+ .withMessage('amount is required')
.isNumeric()
- .exists()
- .withMessage('amount is required'), Committable suggestion
Suggested change
|
||||||||||||
], | ||||||||||||
showFirstValidationError, | ||||||||||||
bridgeController | ||||||||||||
|
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.
Handle cases where
tokenAddressToToken
may returnundefined
The functions
fromTokenInfo = tokenAddressToToken(chain.toString(), fromToken)
andtoTokenInfo = tokenAddressToToken(chain.toString(), toToken)
might returnundefined
if the token address is invalid or not recognized. Using properties likefromTokenInfo.decimals
without validation could lead to runtime errors. It's important to check that these objects are valid before proceeding.Possible action: Add checks to verify that
fromTokenInfo
andtoTokenInfo
are notundefined
and handle the error gracefully if they are.Committable suggestion