synapsecns/sanguine

View on GitHub
packages/rest-api/src/routes/destinationTokensRoute.ts

Summary

Maintainability
A
1 hr
Test Coverage
import express from 'express'
import { check } from 'express-validator'
import { isAddress } from 'ethers/lib/utils'

import { CHAINS_ARRAY } from '../constants/chains'
import { showFirstValidationError } from '../middleware/showFirstValidationError'
import { destinationTokensController } from '../controllers/destinationTokensController'
import { isTokenAddress } from '../utils/isTokenAddress'
import { isTokenSupportedOnChain } from '../utils/isTokenSupportedOnChain'
import { checksumAddresses } from '../middleware/checksumAddresses'
import { normalizeNativeTokenAddress } from '../middleware/normalizeNativeTokenAddress'

const router: express.Router = express.Router()

/**
 * @openapi
 * /destinationTokens:
 *   get:
 *     summary: Get possible destination tokens for a bridge
 *     description: Retrieve possible destination tokens for a given source chain ID and token address
 *     parameters:
 *       - in: query
 *         name: fromChain
 *         required: true
 *         schema:
 *           type: integer
 *         description: The source chain ID
 *       - in: query
 *         name: fromToken
 *         required: true
 *         schema:
 *           type: string
 *         description: The address of the token on the source chain
 *     responses:
 *       200:
 *         description: Successful response
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items:
 *                 type: object
 *                 properties:
 *                   symbol:
 *                     type: string
 *                     description: The token symbol
 *                   chainId:
 *                     type: string
 *                     description: The chain ID where the token is available
 *                   address:
 *                     type: string
 *                     description: The token contract address
 *             example:
 *               - symbol: "USDC"
 *                 chainId: "1"
 *                 address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
 *               - symbol: "USDT"
 *                 chainId: "42161"
 *                 address: "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9"
 *               - symbol: "crvUSD"
 *                 chainId: "8453"
 *                 address: "0x417Ac0e078398C154EdFadD9Ef675d30Be60Af93"
 *       400:
 *         description: Invalid input
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 error:
 *                   type: object
 *                   properties:
 *                     value:
 *                       type: string
 *                     message:
 *                       type: string
 *                     field:
 *                       type: string
 *                     location:
 *                       type: string
 *             example:
 *               error:
 *                 value: "100"
 *                 message: "Unsupported fromChain"
 *                 field: "fromChain"
 *                 location: "query"
 *       500:
 *         description: Server error
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 error:
 *                   type: string
 */

router.get(
  '/',
  normalizeNativeTokenAddress(['fromToken']),
  checksumAddresses(['fromToken']),
  [
    check('fromChain')
      .exists()
      .withMessage('fromChain is required')
      .isNumeric()
      .custom((value) => CHAINS_ARRAY.some((c) => c.id === Number(value)))
      .withMessage('Unsupported fromChain'),
    check('fromToken')
      .exists()
      .withMessage('fromToken is required')
      .custom((value) => isAddress(value))
      .withMessage('Invalid fromToken address')
      .custom((value) => isTokenAddress(value))
      .withMessage('Unsupported fromToken address')
      .custom((value, { req }) =>
        isTokenSupportedOnChain(value, req.query.fromChain as string)
      )
      .withMessage('Token not supported on specified chain'),
  ],
  showFirstValidationError,
  destinationTokensController
)

export default router