diff --git a/api/src/api/controllers/brla.controller.ts b/api/src/api/controllers/brla.controller.ts index a471c94d6..43c4d6554 100644 --- a/api/src/api/controllers/brla.controller.ts +++ b/api/src/api/controllers/brla.controller.ts @@ -1,6 +1,7 @@ import { Request, Response } from 'express'; import { validateMaskedNumber } from 'shared'; import { BrlaEndpoints } from 'shared/src/endpoints/brla.endpoints'; +import httpStatus from 'http-status'; import { BrlaApiService } from '../services/brla/brlaApiService'; import { eventPoller } from '../..'; import { generateReferenceLabel } from '../services/brla/helpers'; @@ -37,18 +38,18 @@ function handleApiError(error: unknown, res: Response, apiMethod: string): void const errorMessageString = splitError[1]; try { const details = JSON.parse(errorMessageString); - res.status(400).json({ error: 'Invalid request', details }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Invalid request', details }); } catch (e) { // The error was not encoded as JSON - res.status(400).json({ error: 'Invalid request', details: errorMessageString }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Invalid request', details: errorMessageString }); } } else { - res.status(400).json({ error: 'Invalid request', details: error.message }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Invalid request', details: error.message }); } return; } - res.status(500).json({ + res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ error: 'Server error', details: error instanceof Error ? error.message : 'Unknown error', }); @@ -75,18 +76,18 @@ export const getBrlaUser = async ( const { taxId } = req.query; if (!taxId) { - res.status(400).json({ error: 'Missing taxId query parameters' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing taxId query parameters' }); return; } const brlaApiService = BrlaApiService.getInstance(); const subaccount = await brlaApiService.getSubaccount(taxId); if (!subaccount) { - res.status(404).json({ error: 'Subaccount not found' }); + res.status(httpStatus.NOT_FOUND).json({ error: 'Subaccount not found' }); return; } if (subaccount.kyc.level < 1) { - res.status(400).json({ error: 'KYC invalid' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'KYC invalid' }); return; } @@ -105,7 +106,7 @@ export const getBrlaUserRemainingLimit = async ( const { taxId } = req.query; if (!taxId) { - res.status(400).json({ error: 'Missing taxId query parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing taxId query parameter' }); return; } @@ -113,14 +114,14 @@ export const getBrlaUserRemainingLimit = async ( const subaccount = await brlaApiService.getSubaccount(taxId); if (!subaccount) { - res.status(404).json({ error: 'Subaccount not found' }); + res.status(httpStatus.NOT_FOUND).json({ error: 'Subaccount not found' }); return; } const totalLimit = subaccount.kyc.limits; const usedLimit = await brlaApiService.getSubaccountUsedLimit(subaccount.id); if (!usedLimit) { - res.status(404).json({ error: 'Limits not found' }); + res.status(httpStatus.NOT_FOUND).json({ error: 'Limits not found' }); return; } @@ -152,7 +153,7 @@ export const triggerBrlaOfframp = async ( const subaccount = await brlaApiService.getSubaccount(taxId); if (!subaccount) { - res.status(404).json({ error: 'Subaccount not found' }); + res.status(httpStatus.NOT_FOUND).json({ error: 'Subaccount not found' }); return; } @@ -162,17 +163,17 @@ export const triggerBrlaOfframp = async ( // validate the recipient's taxId with partial information if (!validateMaskedNumber(pixKeyData.taxId, receiverTaxId)) { - res.status(400).json({ error: 'Invalid pixKey or receiverTaxId' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Invalid pixKey or receiverTaxId' }); return; } } catch (error) { - res.status(400).json({ error: 'Invalid pixKey or receiverTaxId' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Invalid pixKey or receiverTaxId' }); return; } const { limitBurn } = subaccount.kyc.limits; if (Number(amount) > limitBurn) { - res.status(400).json({ error: 'Amount exceeds limit' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Amount exceeds limit' }); return; } @@ -182,7 +183,7 @@ export const triggerBrlaOfframp = async ( amount: Number(amount), taxId: receiverTaxId, }); - res.status(200).json({ offrampId }); + res.status(httpStatus.OK).json({ offrampId }); return; } catch (error) { handleApiError(error, res, 'triggerOfframp'); @@ -197,21 +198,21 @@ export const getOfframpStatus = async ( const { taxId } = req.query; if (!taxId) { - res.status(400).json({ error: 'Missing taxId' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing taxId' }); return; } const brlaApiService = BrlaApiService.getInstance(); const subaccount = await brlaApiService.getSubaccount(taxId); if (!subaccount) { - res.status(400).json({ error: 'Subaccount not found' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Subaccount not found' }); return; } const lastEventCached = await eventPoller.getLatestEventForUser(subaccount.id); if (!lastEventCached) { - res.status(404).json({ error: `No status events found for ${taxId}` }); + res.status(httpStatus.NOT_FOUND).json({ error: `No status events found for ${taxId}` }); return; } @@ -220,11 +221,11 @@ export const getOfframpStatus = async ( lastEventCached.subscription !== 'BURN' && lastEventCached.subscription !== 'BALANCE-UPDATE' ) { - res.status(404).json({ error: `No offramp status event found for ${taxId}` }); + res.status(httpStatus.NOT_FOUND).json({ error: `No offramp status event found for ${taxId}` }); return; } - res.status(200).json({ + res.status(httpStatus.OK).json({ type: lastEventCached.subscription, status: lastEventCached.data.status, }); @@ -243,7 +244,7 @@ export const createSubaccount = async ( const taxId = taxIdType === 'CNPJ' ? cnpj : cpf; if (!taxId) { - res.status(400).json({ error: 'Missing cpf or cnpj' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing cpf or cnpj' }); return; } @@ -258,30 +259,32 @@ export const createSubaccount = async ( // Extra validation for company fields if (taxIdType === 'CNPJ') { if (!req.body.companyName) { - res.status(400).json({ error: 'Missing companyName' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing companyName' }); return; } if (!req.body.cpf) { - res.status(400).json({ error: 'Missing cpf. Partner cpf is required' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing cpf. Partner cpf is required' }); return; } if (startDate === '') { - res.status(400).json({ error: 'Missing startDate' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing startDate' }); return; } } const subaccount = await brlaApiService.getSubaccount(taxId); if (subaccount && subaccount.kyc.level !== 0) { - res.status(400).json({ error: 'Subaccount already created' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Subaccount already created' }); return; - } else if (subaccount && subaccount.kyc.level === 0) { + } + + if (subaccount && subaccount.kyc.level === 0) { logger.info('Subaccount Payload', subaccountPayload); await brlaApiService.retryKYC(subaccount.id, subaccountPayload); lastInteractionMap.set(subaccount.id, Date.now()); - res.status(200).json({ subaccountId: '' }); + res.status(httpStatus.OK).json({ subaccountId: '' }); return; } @@ -305,14 +308,14 @@ export const fetchSubaccountKycStatus = async ( const { taxId } = req.query; if (!taxId) { - res.status(400).json({ error: 'Missing taxId' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing taxId' }); return; } const brlaApiService = BrlaApiService.getInstance(); const subaccount = await brlaApiService.getSubaccount(taxId); if (!subaccount) { - res.status(400).json({ error: 'Subaccount not found' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Subaccount not found' }); return; } @@ -338,7 +341,7 @@ export const fetchSubaccountKycStatus = async ( return; } - res.status(200).json({ + res.status(httpStatus.OK).json({ type: lastEventCached.subscription, status: lastEventCached.data.kycStatus, level: lastEventCached.data.level, @@ -371,19 +374,19 @@ export const getPayInCode = async ( const brlaApiService = BrlaApiService.getInstance(); const subaccount = await brlaApiService.getSubaccount(taxId); if (!subaccount) { - res.status(404).json({ error: 'Subaccount not found' }); + res.status(httpStatus.NOT_FOUND).json({ error: 'Subaccount not found' }); return; } if (subaccount.kyc.level < 1) { - res.status(400).json({ error: 'KYC invalid' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'KYC invalid' }); return; } const { limitMint } = subaccount.kyc.limits; if (Number(amount) > limitMint) { - res.status(400).json({ error: 'Amount exceeds limit' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Amount exceeds limit' }); return; } @@ -393,7 +396,7 @@ export const getPayInCode = async ( referenceLabel: generateReferenceLabel(receiverAddress), }); - res.status(200).json(brCode); + res.status(httpStatus.OK).json(brCode); } catch (error) { handleApiError(error, res, 'triggerOnramp'); } @@ -419,14 +422,14 @@ export const validatePixKey = async ( const { pixKey } = req.query; if (!pixKey) { - res.status(400).json({ error: 'pixKey must be provided' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'pixKey must be provided' }); return; } const brlaApiService = BrlaApiService.getInstance(); await brlaApiService.validatePixKey(pixKey); - res.status(200).json({ valid: true }); + res.status(httpStatus.OK).json({ valid: true }); } catch (error) { handleApiError(error, res, 'validatePixKey'); } @@ -454,19 +457,19 @@ export const startKYC2 = async ( const subaccount = await brlaApiService.getSubaccount(taxId); if (!subaccount) { - res.status(404).json({ error: 'Subaccount not found' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Subaccount not found'}); return; } if (subaccount.kyc.level !== 1) { - res.status(400).json({ error: 'KYC invalid. User must have a valid KYC level 1 status' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'KYC invalid. User must have a valid KYC level 1 status' }); return; } const kycLevel2Response = await kycService.requestKycLevel2(subaccount.id, documentType); lastInteractionMap.set(subaccount.id, Date.now()); - res.status(200).json({ uploadUrls: kycLevel2Response }); + res.status(httpStatus.OK).json({ uploadUrls: kycLevel2Response }); } catch (error) { handleApiError(error, res, 'startKYC2'); } diff --git a/api/src/api/controllers/googleSpreadSheet.controller.ts b/api/src/api/controllers/googleSpreadSheet.controller.ts index e4086ea8b..e029c020a 100644 --- a/api/src/api/controllers/googleSpreadSheet.controller.ts +++ b/api/src/api/controllers/googleSpreadSheet.controller.ts @@ -1,5 +1,6 @@ import 'dotenv/config'; import { Request, Response } from 'express'; +import httpStatus from 'http-status'; import { config } from '../../config/vars'; import { initGoogleSpreadsheet, @@ -40,17 +41,17 @@ export async function storeDataInGoogleSpreadsheet( if (!sheet) { throw new APIError({ message: 'Failed to store data. Sheet unavailable.', - status: 500, + status: httpStatus.INTERNAL_SERVER_ERROR, isPublic: true, }); } await appendData(sheet, req.body); - return res.status(200).json({ message: 'Data stored successfully' }); + return res.status(httpStatus.OK).json({ message: 'Data stored successfully' }); } catch (error) { console.error('Error in storeData:', error); const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; - return res.status(500).json({ + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ error: 'Failed to store data', details: errorMessage, }); diff --git a/api/src/api/controllers/moonbeam.controller.ts b/api/src/api/controllers/moonbeam.controller.ts index 7175dbebd..e5ae9aac8 100644 --- a/api/src/api/controllers/moonbeam.controller.ts +++ b/api/src/api/controllers/moonbeam.controller.ts @@ -3,6 +3,7 @@ import { moonbeam } from 'viem/chains'; import { privateKeyToAccount } from 'viem/accounts'; import Big from 'big.js'; import { Request, Response } from 'express'; +import httpStatus from 'http-status'; import { MoonbeamEndpoints } from 'shared/src/endpoints/moonbeam.endpoints'; import { @@ -63,12 +64,12 @@ export const executeXcmController = async ( return; } catch (error) { console.error('Error executing XCM:', error); - res.status(400).json({ error: 'Invalid transaction' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Invalid transaction' }); return; } } catch (error) { console.error('Error executing XCM:', error); - res.status(500).json({ error: 'Internal Server Error' }); + res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ error: 'Internal Server Error' }); } }; diff --git a/api/src/api/controllers/pendulum.controller.ts b/api/src/api/controllers/pendulum.controller.ts index 13e4c47b6..88586d19a 100644 --- a/api/src/api/controllers/pendulum.controller.ts +++ b/api/src/api/controllers/pendulum.controller.ts @@ -1,6 +1,7 @@ import Big from 'big.js'; import { AccountInfo } from '@polkadot/types/interfaces'; import { Request, Response } from 'express'; +import httpStatus from 'http-status'; import { StellarTokenConfig, TOKEN_CONFIG, XCMTokenConfig } from 'shared'; import { PendulumEndpoints } from 'shared/src/endpoints/pendulum.endpoints'; @@ -24,7 +25,7 @@ export const fundEphemeralAccountController = async ( const networkName = 'pendulum'; if (!ephemeralAddress) { - res.status(400).send({ error: 'Invalid request parameters' }); + res.status(httpStatus.BAD_REQUEST).send({ error: 'Invalid request parameters' }); return; } @@ -34,11 +35,11 @@ export const fundEphemeralAccountController = async ( res.json({ status: 'success', data: undefined }); return; } - res.status(500).send({ error: 'Funding error' }); + res.status(httpStatus.INTERNAL_SERVER_ERROR).send({ error: 'Funding error' }); return; } catch (error) { console.error('Error funding ephemeral account:', error); - res.status(500).send({ error: 'Internal Server Error' }); + res.status(httpStatus.INTERNAL_SERVER_ERROR).send({ error: 'Internal Server Error' }); } }; diff --git a/api/src/api/controllers/price.controller.ts b/api/src/api/controllers/price.controller.ts index b77d4b9c1..f37c51fe9 100644 --- a/api/src/api/controllers/price.controller.ts +++ b/api/src/api/controllers/price.controller.ts @@ -1,4 +1,5 @@ import { RequestHandler } from 'express'; +import httpStatus from 'http-status'; import { PriceEndpoints } from 'shared/src/endpoints/price.endpoints'; import * as alchemyPayService from '../services/alchemypay/alchemypay.service'; @@ -45,24 +46,24 @@ export const getPriceForProvider: RequestHandler { const { accountId, maxTime, assetCode, baseFee } = req.body as CreationBody; if (!accountId || !maxTime) { - res.status(400).json({ error: 'Missing accountId or maxTime parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing accountId or maxTime parameter' }); return; } if (!assetCode) { - res.status(400).json({ error: 'Missing assetCode parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing assetCode parameter' }); return; } if (!baseFee) { - res.status(400).json({ error: 'Missing baseFee parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing baseFee parameter' }); return; } if (typeof maxTime !== 'number') { - res.status(400).json({ error: 'maxTime must be a number' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'maxTime must be a number' }); return; } next(); @@ -85,31 +86,31 @@ export const validateBundledPriceInput: RequestHandler<{}, unknown, unknown, Pri const { fromCrypto, toFiat, amount, network } = req.query; if (!fromCrypto || !PriceEndpoints.isValidCryptoCurrency(fromCrypto)) { - res.status(400).json({ + res.status(httpStatus.BAD_REQUEST).json({ error: `Invalid fromCrypto. Supported currencies are: ${PriceEndpoints.VALID_CRYPTO_CURRENCIES.join(', ')}`, }); return; } if (!toFiat || !PriceEndpoints.isValidFiatCurrency(toFiat)) { - res.status(400).json({ + res.status(httpStatus.BAD_REQUEST).json({ error: `Invalid toFiat. Supported currencies are: ${PriceEndpoints.VALID_FIAT_CURRENCIES.join(', ')}`, }); return; } if (!amount) { - res.status(400).json({ error: 'Missing amount parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing amount parameter' }); return; } if (!network) { - res.status(400).json({ error: 'Missing network parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing network parameter' }); return; } if (isNaN(parseFloat(amount))) { - res.status(400).json({ error: 'Invalid amount parameter. Not a number.' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Invalid amount parameter. Not a number.' }); return; } @@ -120,38 +121,38 @@ export const validatePriceInput: RequestHandler<{}, unknown, unknown, PriceQuery const { provider, fromCrypto, toFiat, amount, network } = req.query; if (!provider || !PriceEndpoints.isValidProvider(provider)) { - res.status(400).json({ + res.status(httpStatus.BAD_REQUEST).json({ error: `Invalid provider. Supported providers are: ${PriceEndpoints.VALID_PROVIDERS.join(', ')}`, }); return; } if (!fromCrypto || !PriceEndpoints.isValidCryptoCurrency(fromCrypto)) { - res.status(400).json({ + res.status(httpStatus.BAD_REQUEST).json({ error: `Invalid fromCrypto. Supported currencies are: ${PriceEndpoints.VALID_CRYPTO_CURRENCIES.join(', ')}`, }); return; } if (!toFiat || !PriceEndpoints.isValidFiatCurrency(toFiat)) { - res.status(400).json({ + res.status(httpStatus.BAD_REQUEST).json({ error: `Invalid toFiat. Supported currencies are: ${PriceEndpoints.VALID_FIAT_CURRENCIES.join(', ')}`, }); return; } if (!amount) { - res.status(400).json({ error: 'Missing amount parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing amount parameter' }); return; } if (!network) { - res.status(400).json({ error: 'Missing network parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing network parameter' }); return; } if (isNaN(parseFloat(amount))) { - res.status(400).json({ error: 'Invalid amount parameter. Not a number.' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Invalid amount parameter. Not a number.' }); return; } @@ -162,22 +163,22 @@ export const validateChangeOpInput: RequestHandler = (req, res, next) => { const { accountId, sequence, paymentData, maxTime, assetCode, baseFee } = req.body as ChangeOpBody; if (!accountId || !sequence || !paymentData || !maxTime) { - res.status(400).json({ error: 'Missing required parameters' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing required parameters' }); return; } if (!assetCode) { - res.status(400).json({ error: 'Missing assetCode parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing assetCode parameter' }); return; } if (!baseFee) { - res.status(400).json({ error: 'Missing baseFee parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing baseFee parameter' }); return; } if (typeof sequence !== 'string' || typeof maxTime !== 'number') { - res.status(400).json({ error: 'Invalid input types' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Invalid input types' }); return; } next(); @@ -187,12 +188,12 @@ const validateRequestBodyValuesForTransactionStore = (): RequestHandler => (req, const { flowType } = req.body; if (!flowType) { - res.status(400).json({ error: 'Missing flowType parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing flowType parameter' }); return; } if (!FLOW_HEADERS[flowType as keyof typeof FLOW_HEADERS]) { - res.status(400).json({ + res.status(httpStatus.BAD_REQUEST).json({ error: `Invalid flowType. Supported flowTypes are: ${Object.keys(FLOW_HEADERS).join(', ')}`, }); return; @@ -212,7 +213,7 @@ const validateRequestBodyValues = const missingItems = requiredRequestBodyKeys.filter((key) => !data[key]); const errorMessage = `Request body data does not match schema. Missing items: ${missingItems.join(', ')}`; console.error(errorMessage); - res.status(400).json({ error: errorMessage }); + res.status(httpStatus.BAD_REQUEST).json({ error: errorMessage }); return; } @@ -228,17 +229,17 @@ export const validatePreSwapSubsidizationInput: RequestHandler = (req, res, next const { amountRaw, address } = req.body as SwapBody; if (amountRaw === undefined) { - res.status(400).json({ error: 'Missing "amountRaw" parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing "amountRaw" parameter' }); return; } if (typeof amountRaw !== 'string') { - res.status(400).json({ error: '"amountRaw" parameter must be a string' }); + res.status(httpStatus.BAD_REQUEST).json({ error: '"amountRaw" parameter must be a string' }); return; } if (address === undefined) { - res.status(400).json({ error: 'Missing "address" parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing "address" parameter' }); return; } @@ -249,22 +250,22 @@ export const validatePostSwapSubsidizationInput: RequestHandler = (req, res, nex const { amountRaw, address, token } = req.body as Required; if (amountRaw === undefined) { - res.status(400).json({ error: 'Missing "amountRaw" parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing "amountRaw" parameter' }); return; } if (typeof amountRaw !== 'string') { - res.status(400).json({ error: '"amountRaw" parameter must be a string' }); + res.status(httpStatus.BAD_REQUEST).json({ error: '"amountRaw" parameter must be a string' }); return; } if (address === undefined) { - res.status(400).json({ error: 'Missing "address" parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing "address" parameter' }); return; } if (token === undefined) { - res.status(400).json({ error: 'Missing "token" parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing "token" parameter' }); return; } @@ -275,17 +276,17 @@ export const validateSep10Input: RequestHandler = (req, res, next) => { const { challengeXDR, outToken, clientPublicKey } = req.body as Sep10Body; if (!challengeXDR) { - res.status(400).json({ error: 'Missing Anchor challenge: challengeXDR' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing Anchor challenge: challengeXDR' }); return; } if (!outToken) { - res.status(400).json({ error: 'Missing offramp token identifier: outToken' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing offramp token identifier: outToken' }); return; } if (!clientPublicKey) { - res.status(400).json({ error: 'Missing Stellar ephemeral public key: clientPublicKey' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing Stellar ephemeral public key: clientPublicKey' }); return; } next(); @@ -295,7 +296,7 @@ export const validateSiweCreate: RequestHandler = (req, res, next) => { const { walletAddress } = req.body as SiweCreateBody; if (!walletAddress) { - res.status(400).json({ error: 'Missing param: walletAddress' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing param: walletAddress' }); return; } next(); @@ -305,17 +306,17 @@ export const validateSiweValidate: RequestHandler = (req, res, next) => { const { nonce, signature, siweMessage } = req.body as SiweValidateBody; if (!signature) { - res.status(400).json({ error: 'Missing param: signature' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing param: signature' }); return; } if (!nonce) { - res.status(400).json({ error: 'Missing param: nonce' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing param: nonce' }); return; } if (!siweMessage) { - res.status(400).json({ error: 'Missing param: siweMessage' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing param: siweMessage' }); return; } @@ -326,22 +327,22 @@ export const validateBrlaTriggerOfframpInput: RequestHandler = (req, res, next) const { taxId, pixKey, amount, receiverTaxId } = req.body as TriggerOfframpRequest; if (!taxId) { - res.status(400).json({ error: 'Missing taxId parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing taxId parameter' }); return; } if (!pixKey) { - res.status(400).json({ error: 'Missing pixKey parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing pixKey parameter' }); return; } if (!amount || isNaN(Number(amount))) { - res.status(400).json({ error: 'Missing or invalid amount parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing or invalid amount parameter' }); return; } if (!receiverTaxId) { - res.status(400).json({ error: 'Missing receiverTaxId parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing receiverTaxId parameter' }); return; } @@ -353,50 +354,50 @@ export const validataSubaccountCreation: RequestHandler = (req, res, next) => { req.body as RegisterSubaccountPayload; if (taxIdType !== 'CPF' && taxIdType !== 'CNPJ') { - res.status(400).json({ error: 'taxIdType parameter must be either CPF or CNPJ' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'taxIdType parameter must be either CPF or CNPJ' }); return; } if (!cpf) { - res.status(400).json({ + res.status(httpStatus.BAD_REQUEST).json({ error: "Missing cpf parameter. If taxIdType is CNPJ, should be a partner's CPF", }); return; } if (!phone) { - res.status(400).json({ error: 'Missing phone parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing phone parameter' }); return; } if (!address) { - res.status(400).json({ error: 'Missing address parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing address parameter' }); return; } if (!fullName) { - res.status(400).json({ error: 'Missing fullName parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing fullName parameter' }); return; } if (!birthdate) { - res.status(400).json({ error: 'Missing birthdate parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing birthdate parameter' }); return; } // CNPJ specific validations if (taxIdType === 'CNPJ' && !companyName) { - res.status(400).json({ error: 'Missing companyName parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing companyName parameter' }); return; } if (taxIdType === 'CNPJ' && !startDate) { - res.status(400).json({ error: 'Missing startDate parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing startDate parameter' }); return; } if (taxIdType === 'CNPJ' && !cnpj) { - res.status(400).json({ error: 'Missing cnpj parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing cnpj parameter' }); return; } @@ -407,17 +408,17 @@ export const validateGetPayInCode: RequestHandler = (req, res, next) => { const { taxId, receiverAddress, amount } = req.query as PayInCodeQuery; if (!taxId) { - res.status(400).json({ error: 'Missing taxId parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing taxId parameter' }); return; } if (!amount || isNaN(Number(amount))) { - res.status(400).json({ error: 'Missing or invalid amount parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing or invalid amount parameter' }); return; } if (!receiverAddress || !(receiverAddress as string).startsWith('0x')) { - res.status(400).json({ + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing or invalid receiverAddress parameter. receiverAddress must be a valid Evm address', }); return; @@ -430,14 +431,14 @@ export const validateStartKyc2: RequestHandler = (req, res, next) => { const { taxId, documentType } = req.body as BrlaEndpoints.StartKYC2Request; if (!taxId) { - res.status(400).json({ error: 'Missing taxId parameter' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Missing taxId parameter' }); return; } if (!isValidKYCDocType(documentType)) { - res.status(400).json({ error: 'Invalid document type. Document type must be: RG or CNH' }); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Invalid document type. Document type must be: RG or CNH' }); return; } next(); -}; +}; \ No newline at end of file diff --git a/api/src/api/services/slack.service.ts b/api/src/api/services/slack.service.ts index 06ec37bc6..042dca077 100644 --- a/api/src/api/services/slack.service.ts +++ b/api/src/api/services/slack.service.ts @@ -1,6 +1,10 @@ // 6 hours in milliseconds const COOLDOWN_PERIOD_MS = 6 * 60 * 60 * 1000; +function generateMessageSignature(message: SlackMessage): string { + return JSON.stringify(message); +} + export interface SlackMessage { text: string; [key: string]: unknown; @@ -20,10 +24,6 @@ export class SlackNotifier { this.messageHistory = new Map(); } - private generateMessageSignature(message: SlackMessage): string { - return JSON.stringify(message); - } - private isMessageAllowed(signature: string): boolean { const now = Date.now(); const lastSent = this.messageHistory.get(signature); @@ -34,7 +34,15 @@ export class SlackNotifier { } public async sendMessage(message: SlackMessage): Promise { - const signature = this.generateMessageSignature(message); + + const slackUserId = process.env.SLACK_USER_ID; + + const messageWithUserTag = { + ...message, + text: slackUserId ? `<@${slackUserId}> ${message.text}` : message.text, + }; + + const signature = generateMessageSignature(messageWithUserTag); if (!this.isMessageAllowed(signature)) { // Message is still in cooldown period, skip sending diff --git a/api/webhooks-cache/index.js b/api/webhooks-cache/index.js index 6b51b6666..4fb03f942 100644 --- a/api/webhooks-cache/index.js +++ b/api/webhooks-cache/index.js @@ -1,5 +1,6 @@ const express = require('express'); const bodyParser = require('body-parser'); +const httpStatus = require('http-status'); const app = express(); const PORT = process.env.PORT || 3000; @@ -19,7 +20,7 @@ function authMiddleware(req, res, next) { return next(); } - return res.status(401).json({ error: 'Unauthorized' }); + return res.status(httpStatus.UNAUTHORIZED).json({ error: 'Unauthorized' }); } const checkDomain = (req, res, next) => { @@ -34,7 +35,7 @@ const checkDomain = (req, res, next) => { } console.log(origin); - return res.status(403).json({ error: 'Access denied. Domain not allowed to post events' }); + return res.status(httpStatus.FORBIDDEN).json({ error: 'Access denied. Domain not allowed to post events' }); }; app.post('*', checkDomain, (req, res) => { @@ -45,7 +46,7 @@ app.post('*', checkDomain, (req, res) => { } console.log('Event received:', req.body); - res.status(200).send('Event recorded'); + res.status(httpStatus.OK).send('Event recorded'); }); app.get('/events', authMiddleware, (req, res) => { diff --git a/frontend/_redirects b/frontend/_redirects index 5f7fe6265..84fddfbfe 100644 --- a/frontend/_redirects +++ b/frontend/_redirects @@ -1,3 +1,3 @@ /api/production/* https://api.vortexfinance.co/:splat 200 -/api/staging/* https://api-staging.vortexfinance.co/:splat 200 +/api/staging/* https://api-staging.prd.vortexfinance.co/:splat 200 /* /index.html 200 diff --git a/frontend/src/components/AirdropBanner/index.tsx b/frontend/src/components/AirdropBanner/index.tsx index e456f3d43..ae6512a8d 100644 --- a/frontend/src/components/AirdropBanner/index.tsx +++ b/frontend/src/components/AirdropBanner/index.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import { motion, AnimatePresence } from 'motion/react'; import { useTranslation, Trans } from 'react-i18next'; import { ChevronDownIcon } from '@heroicons/react/20/solid'; + export const AirdropBanner = () => { const { t } = useTranslation(); const [expanded, setExpanded] = useState(false); @@ -49,7 +50,10 @@ export const AirdropBanner = () => { animate={{ opacity: 1, x: 0 }} transition={{ delay: 0.1 }} > - {t('components.airdropBanner.list.1')} + + All eligible users get $10 USDT - the first 100 receive a 10 bonus, totaling 20 USDT.{' '} + Rewards go to your wallet on Base or AssetHub. + { transition={{ delay: 0.2 }} > - All eligible users get $10 USDT - the first 100 receive a 10 bonus, totaling 20 USDT.{' '} - Rewards go to your wallet on Base or AssetHub. + One reward per person, paid out every 24 hours – Check your status + e.stopPropagation()} + rel="noreferrer" + > + {' '} + here + + . { transition={{ delay: 0.3 }} > - One reward per person - Check + Your trust matters – Vortex is e.stopPropagation()} rel="noreferrer" > - {' '} - here + open source {' '} - (Updates every 24hrs) + for full transparency. diff --git a/frontend/src/components/RampToggle/index.tsx b/frontend/src/components/RampToggle/index.tsx index d54533c3f..8e1a5f30d 100644 --- a/frontend/src/components/RampToggle/index.tsx +++ b/frontend/src/components/RampToggle/index.tsx @@ -32,7 +32,7 @@ export const RampToggle = ({ activeDirection, onToggle }: RampToggleProps) => { > {t('components.swap.sellButton')} - +