Skip to content

Commit fdfcc06

Browse files
committed
feat: improve error handling, refactor folders
1 parent 839bb6f commit fdfcc06

35 files changed

+170
-113
lines changed

src/api-docs/openAPIDocumentGenerator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import {
33
OpenApiGeneratorV3,
44
} from "@asteasolutions/zod-to-openapi"
55

6-
import { healthCheckRegistry } from "@/api/healthCheck/healthCheckRouter"
7-
import { swapRegistry } from "@/api/swap/swapRouter"
6+
import { healthCheckRegistry } from "@/api/routes/healthCheck/healthCheckRouter"
7+
import { swapRegistry } from "@/api/routes/swap/swapRouter"
88

99
export function generateOpenAPIDocument() {
1010
const registry = new OpenAPIRegistry([healthCheckRegistry, swapRegistry])

src/api/swap/swapModel.ts renamed to src/api/routes/swap/swapModel.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SwapVerificationType, SwapperMode } from "@/swap/interface"
1+
import { SwapVerificationType, SwapperMode } from "@/swapService/interface"
22
import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi"
33
import { InvalidAddressError, getAddress, isHex } from "viem"
44
import { z } from "zod"
@@ -150,7 +150,7 @@ const getSwapSchema = z.object({
150150
.string()
151151
.transform((s) => JSON.parse(s))
152152
.pipe(chainRoutingConfigSchema)
153-
.optional(), // TODO handle routing config
153+
.optional(),
154154
}),
155155
})
156156

src/api/routes/swap/swapRouter.ts

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { OpenAPIRegistry } from "@asteasolutions/zod-to-openapi"
2+
import express, { type Router, type Request, type Response } from "express"
3+
4+
import { createApiResponse } from "@/api-docs/openAPIResponseBuilders"
5+
6+
import { ServiceResponse } from "@/common/models/serviceResponse"
7+
import {
8+
handleServiceResponse,
9+
validateRequest,
10+
} from "@/common/utils/httpHandlers"
11+
import { runPipeline } from "@/swapService/runner"
12+
import type { SwapParams } from "@/swapService/types"
13+
import {
14+
ApiError,
15+
addInOutDeposits,
16+
findToken,
17+
getSwapper,
18+
} from "@/swapService/utils"
19+
import { StatusCodes } from "http-status-codes"
20+
import { InvalidAddressError, isHex } from "viem"
21+
import { z } from "zod"
22+
import {
23+
type SwapResponse,
24+
getSwapSchema,
25+
swapResponseSchema,
26+
} from "./swapModel"
27+
28+
export const swapRegistry = new OpenAPIRegistry()
29+
export const swapRouter: Router = express.Router()
30+
31+
swapRegistry.register("Swap", swapResponseSchema)
32+
swapRegistry.registerPath({
33+
method: "get",
34+
path: "/swap",
35+
tags: ["Swap"],
36+
request: { query: getSwapSchema.shape.query },
37+
responses: createApiResponse(swapResponseSchema, "Success"),
38+
})
39+
40+
swapRouter.get(
41+
"/",
42+
validateRequest(getSwapSchema),
43+
async (req: Request, res: Response) => {
44+
const serviceResponse = await findSwap(req)
45+
return handleServiceResponse(serviceResponse, res)
46+
},
47+
)
48+
49+
async function findSwap(
50+
req: Request,
51+
): Promise<ServiceResponse<SwapResponse | null>> {
52+
try {
53+
const swapParams = parseRequest(req)
54+
55+
let data = await runPipeline(swapParams)
56+
57+
// GLOBAL CHECKS
58+
data = addInOutDeposits(swapParams, data)
59+
60+
// make sure verify item includes at least a function selector
61+
if (
62+
!isHex(data.verify.verifierData) ||
63+
data.verify.verifierData.length < 10
64+
)
65+
throw new ApiError(
66+
StatusCodes.INTERNAL_SERVER_ERROR,
67+
"Verifier transaction is empty",
68+
)
69+
70+
return ServiceResponse.success<SwapResponse>(data)
71+
} catch (error) {
72+
if (error instanceof ApiError) {
73+
return ServiceResponse.failure(
74+
error.message,
75+
error.statusCode,
76+
error.data,
77+
)
78+
}
79+
return ServiceResponse.failure(
80+
`${error}`,
81+
StatusCodes.INTERNAL_SERVER_ERROR,
82+
)
83+
}
84+
}
85+
86+
function parseRequest(request: Request): SwapParams {
87+
try {
88+
const { query: validatedParams } = getSwapSchema.parse(request)
89+
90+
// TODO
91+
// if (!isSupportedChainId(validatedParams.chainId)) {
92+
// throw new Error("Unsupported chainId")
93+
// }
94+
95+
const chainId = validatedParams.chainId
96+
const tokenIn = findToken(chainId, validatedParams.tokenIn)
97+
if (!tokenIn)
98+
throw new ApiError(StatusCodes.NOT_FOUND, "Token in not supported")
99+
100+
const tokenOut = findToken(chainId, validatedParams.tokenOut)
101+
if (!tokenOut)
102+
throw new ApiError(StatusCodes.NOT_FOUND, "Token out not supported")
103+
104+
return {
105+
...validatedParams,
106+
from: getSwapper(chainId),
107+
chainId,
108+
tokenIn,
109+
tokenOut,
110+
}
111+
} catch (error) {
112+
if (error instanceof ApiError) throw error
113+
if (error instanceof z.ZodError) {
114+
throw new ApiError(
115+
StatusCodes.BAD_REQUEST,
116+
`Invalid parameters: ${error.errors.map((e) => e.message).join(", ")}`,
117+
)
118+
}
119+
if (error instanceof InvalidAddressError)
120+
throw new ApiError(400, "Invalid Address")
121+
122+
throw new ApiError(500, `${error}`)
123+
}
124+
}

src/api/swap/swapRouter.ts

Lines changed: 0 additions & 93 deletions
This file was deleted.

src/common/models/serviceResponse.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ export class ServiceResponse<T = null> {
2323
return new ServiceResponse(true, data, statusCode)
2424
}
2525

26-
static failure<T>(
26+
static failure(
2727
message: string,
28-
data: T,
2928
statusCode: number = StatusCodes.BAD_REQUEST,
29+
data?: any,
3030
) {
3131
return new ServiceResponse(false, data, statusCode, message)
3232
}

src/common/utils/contractBook.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as chains from "viem/chains"
2-
// TODO
2+
33
const contractBook: any = {
44
swapper: {
55
abi: require("./abi/Swapper.json"),

src/common/utils/envConfig.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,4 @@ export const env = cleanEnv(process.env, {
1313
CORS_ORIGIN: str({ devDefault: testOnly("http://localhost:3001") }),
1414
COMMON_RATE_LIMIT_MAX_REQUESTS: num({ devDefault: testOnly(1000) }),
1515
COMMON_RATE_LIMIT_WINDOW_MS: num({ devDefault: testOnly(1000) }),
16-
// TODO
1716
})

src/common/utils/tokenLIst_1.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@
146146
"name": "Renzo Restaked ETH",
147147
"symbol": "EZETH",
148148
"decimals": 18,
149-
"logoURI": "https://coin-images.coingecko.com/coins/images/34753/large/Ezeth_logo_circle.png?1713496404",
149+
"logoURI": "https://coin-images.coingecko.com/coins/images/34753/large/Ezeth_logo_circle.png?1713496StatusCodes.NOT_FOUND",
150150
"meta": {}
151151
},
152152
{
@@ -948,7 +948,7 @@
948948
"meta": {}
949949
},
950950
{
951-
"addressInfo": "0x64047dd3288276d70a4f8b5df54668c8403f877f",
951+
"addressInfo": "0x6StatusCodes.NOT_FOUND7dd3288276d70a4f8b5df54668c8403f877f",
952952
"chainId": 1,
953953
"name": "Amphor Restaked BTC",
954954
"symbol": "amphrBTC",

src/server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import helmet from "helmet"
44
import { pino } from "pino"
55

66
import { openAPIRouter } from "@/api-docs/openAPIRouter"
7-
import { healthCheckRouter } from "@/api/healthCheck/healthCheckRouter"
8-
import { swapRouter } from "@/api/swap/swapRouter"
7+
import { healthCheckRouter } from "@/api/routes/healthCheck/healthCheckRouter"
8+
import { swapRouter } from "@/api/routes/swap/swapRouter"
99
import errorHandler from "@/common/middleware/errorHandler"
1010
import rateLimiter from "@/common/middleware/rateLimiter"
1111
import requestLogger from "@/common/middleware/requestLogger"

0 commit comments

Comments
 (0)