diff --git a/packages/rest-api/src/controllers/bridgeController.ts b/packages/rest-api/src/controllers/bridgeController.ts index 568c4eb0fc..f69c8715f0 100644 --- a/packages/rest-api/src/controllers/bridgeController.ts +++ b/packages/rest-api/src/controllers/bridgeController.ts @@ -11,7 +11,14 @@ export const bridgeController = async (req, res) => { return res.status(400).json({ errors: errors.array() }) } try { - const { fromChain, toChain, amount, fromToken, toToken } = req.query + const { + fromChain, + toChain, + amount, + fromToken, + toToken, + originUserAddress, + } = req.query const fromTokenInfo = tokenAddressToToken(fromChain.toString(), fromToken) const toTokenInfo = tokenAddressToToken(toChain.toString(), toToken) @@ -23,7 +30,10 @@ export const bridgeController = async (req, res) => { Number(toChain), fromToken, toToken, - amountInWei + amountInWei, + originUserAddress + ? { originUserAddress: originUserAddress.toString() } + : {} ) const payload = resp.map((quote) => { diff --git a/packages/rest-api/src/controllers/bridgeTxInfoController.ts b/packages/rest-api/src/controllers/bridgeTxInfoController.ts index 0a0b4bc7bc..01a56f01ca 100644 --- a/packages/rest-api/src/controllers/bridgeTxInfoController.ts +++ b/packages/rest-api/src/controllers/bridgeTxInfoController.ts @@ -11,8 +11,15 @@ export const bridgeTxInfoController = async (req, res) => { } try { - const { fromChain, toChain, amount, destAddress, fromToken, toToken } = - req.query + const { + fromChain, + toChain, + amount, + destAddress, + fromToken, + toToken, + originUserAddress, + } = req.query const fromTokenInfo = tokenAddressToToken(fromChain.toString(), fromToken) @@ -23,7 +30,10 @@ export const bridgeTxInfoController = async (req, res) => { Number(toChain), fromToken, toToken, - amountInWei + amountInWei, + originUserAddress + ? { originUserAddress: originUserAddress.toString() } + : {} ) const txInfoArray = await Promise.all( diff --git a/packages/rest-api/src/routes/bridgeRoute.ts b/packages/rest-api/src/routes/bridgeRoute.ts index 0e4a88b947..5c5d7b6c65 100644 --- a/packages/rest-api/src/routes/bridgeRoute.ts +++ b/packages/rest-api/src/routes/bridgeRoute.ts @@ -1,5 +1,6 @@ import express from 'express' import { check } from 'express-validator' +import { isAddress } from 'ethers/lib/utils' import { isTokenAddress } from '../utils/isTokenAddress' import { CHAINS_ARRAY } from '../constants/chains' @@ -49,6 +50,12 @@ const router = express.Router() * schema: * type: number * description: The amount of tokens to bridge + * - in: query + * name: originUserAddress + * required: false + * schema: + * type: string + * description: The address of the user on the origin chain * responses: * 200: * description: Successful response @@ -230,6 +237,10 @@ router.get( return validateRouteExists(fromChain, fromToken, toChain, toToken) }) .withMessage('No valid route exists for the chain/token combination'), + check('originUserAddress') + .optional() + .custom((value) => isAddress(value)) + .withMessage('Invalid originUserAddress address'), ], showFirstValidationError, bridgeController diff --git a/packages/rest-api/src/routes/bridgeTxInfoRoute.ts b/packages/rest-api/src/routes/bridgeTxInfoRoute.ts index 5a0ce30326..44b6904e08 100644 --- a/packages/rest-api/src/routes/bridgeTxInfoRoute.ts +++ b/packages/rest-api/src/routes/bridgeTxInfoRoute.ts @@ -56,6 +56,12 @@ const router = express.Router() * schema: * type: string * description: The destination address for the bridged tokens + * - in: query + * name: originUserAddress + * required: false + * schema: + * type: string + * description: The address of the user on the origin chain * responses: * 200: * description: Successful response @@ -171,6 +177,10 @@ router.get( return validateRouteExists(fromChain, fromToken, toChain, toToken) }) .withMessage('No valid route exists for the chain/token combination'), + check('originUserAddress') + .optional() + .custom((value) => isAddress(value)) + .withMessage('Invalid originUserAddress address'), ], showFirstValidationError, bridgeTxInfoController diff --git a/packages/rest-api/src/tests/bridgeRoute.test.ts b/packages/rest-api/src/tests/bridgeRoute.test.ts index 3617d5d71b..542feab63a 100644 --- a/packages/rest-api/src/tests/bridgeRoute.test.ts +++ b/packages/rest-api/src/tests/bridgeRoute.test.ts @@ -25,6 +25,23 @@ describe('Bridge Route with Real Synapse Service', () => { expect(response.body[0]).toHaveProperty('bridgeFeeFormatted') }, 15000) + it('should return bridge quotes for valid originUserAddress', async () => { + const response = await request(app).get('/bridge').query({ + fromChain: '1', + toChain: '10', + fromToken: USDC.addresses[1], + toToken: USDC.addresses[10], + amount: '1000', + originUserAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', + }) + + expect(response.status).toBe(200) + expect(Array.isArray(response.body)).toBe(true) + expect(response.body.length).toBeGreaterThan(0) + expect(response.body[0]).toHaveProperty('maxAmountOutStr') + expect(response.body[0]).toHaveProperty('bridgeFeeFormatted') + }, 15000) + it('should return bridge quotes for ZeroAddress', async () => { const response = await request(app).get('/bridge').query({ fromChain: '1', @@ -56,6 +73,23 @@ describe('Bridge Route with Real Synapse Service', () => { expect(response.body[0]).toHaveProperty('bridgeFeeFormatted') }, 15000) + it('should return 400 for invalid originUserAddress', async () => { + const response = await request(app).get('/bridge').query({ + fromChain: '1', + toChain: '10', + fromToken: USDC.addresses[1], + toToken: USDC.addresses[10], + amount: '1000', + originUserAddress: 'invalid_address', + }) + + expect(response.status).toBe(400) + expect(response.body.error).toHaveProperty( + 'message', + 'Invalid originUserAddress address' + ) + }, 15000) + it('should return 400 for unsupported route', async () => { const response = await request(app).get('/bridge').query({ fromChain: '1', diff --git a/packages/rest-api/src/tests/bridgeTxInfoRoute.test.ts b/packages/rest-api/src/tests/bridgeTxInfoRoute.test.ts index 9f5d183bbe..e39450e725 100644 --- a/packages/rest-api/src/tests/bridgeTxInfoRoute.test.ts +++ b/packages/rest-api/src/tests/bridgeTxInfoRoute.test.ts @@ -29,6 +29,45 @@ describe('Bridge TX Info Route', () => { ) }, 10_000) + it('should return bridge transaction info for valid input with valid originUserAddress', async () => { + const response = await request(app).get('/bridgeTxInfo').query({ + fromChain: '1', + toChain: '137', + fromToken: USDC.addresses[1], + toToken: USDC.addresses[137], + amount: '1000', + destAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', + originUserAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', + }) + + expect(response.status).toBe(200) + expect(Array.isArray(response.body)).toBe(true) + expect(response.body.length).toBeGreaterThan(0) + expect(response.body[0]).toHaveProperty('data') + expect(response.body[0]).toHaveProperty( + 'to', + '0xd5a597d6e7ddf373a92C8f477DAAA673b0902F48' + ) + }, 10_000) + + it('should return 400 for invalid originUserAddress', async () => { + const response = await request(app).get('/bridgeTxInfo').query({ + fromChain: '1', + toChain: '137', + fromToken: USDC.addresses[1], + toToken: USDC.addresses[137], + amount: '1000', + destAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e', + originUserAddress: 'invalid_address', + }) + + expect(response.status).toBe(400) + expect(response.body.error).toHaveProperty( + 'message', + 'Invalid originUserAddress address' + ) + }, 10_000) + it('should return 400 for unsupported route', async () => { const response = await request(app).get('/bridgeTxInfo').query({ fromChain: '1',