Skip to content

Commit faf9f9c

Browse files
authored
fix ccip config api (#2966)
1 parent 776a619 commit faf9f9c

File tree

5 files changed

+100
-16
lines changed

5 files changed

+100
-16
lines changed

src/pages/api/ccip/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface ChainDetails {
3939
tokenPoolFactory?: string
4040
feeQuoter?: string
4141
rmnPermeable?: boolean
42+
mcms?: string
4243
}
4344

4445
export type ChainApiResponse = {

src/pages/api/ccip/utils.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ChainsConfig, Environment, loadReferenceData, Version } from "@config/d
44
import { SupportedChain } from "@config/index.ts"
55
import { directoryToSupportedChain } from "@features/utils/index.ts"
66
import { v4 as uuidv4 } from "uuid"
7-
import type { TokenMetadata } from "./types/index.ts"
7+
import type { TokenMetadata, ChainType, OutputKeyType } from "./types/index.ts"
88

99
export const prerender = false
1010

@@ -264,6 +264,16 @@ export const validateOutputKey = (outputKey?: string): "chainId" | "selector" |
264264
return outputKey as "chainId" | "selector" | "internalId"
265265
}
266266

267+
export const generateChainKey = (chainId: number | string, chainType: ChainType, outputKey: OutputKeyType): string => {
268+
const chainIdStr = chainId.toString()
269+
270+
if (outputKey === "chainId" && chainType !== "evm" && chainType !== "solana") {
271+
return `${chainType}-${chainIdStr}`
272+
}
273+
274+
return chainIdStr
275+
}
276+
267277
/**
268278
* Handles API errors and converts them to standardized responses
269279
* @param error - Error to handle

src/pages/api/ccip/v1/chains.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
validateEnvironment,
44
validateFilters,
55
validateOutputKey,
6+
generateChainKey,
67
createMetadata,
78
handleApiError,
89
successHeaders,
@@ -90,7 +91,12 @@ export const GET: APIRoute = async ({ request }) => {
9091
(acc, [family, chainList]) => {
9192
acc[family] = chainList.reduce(
9293
(familyAcc, chain) => {
93-
const key = outputKey ? chain[outputKey].toString() : chain.internalId
94+
const key =
95+
outputKey === "chainId"
96+
? generateChainKey(chain.chainId, chain.chainType, outputKey)
97+
: outputKey
98+
? chain[outputKey].toString()
99+
: chain.internalId
94100
familyAcc[key] = chain
95101
return familyAcc
96102
},

src/pages/api/services/chain-data.ts

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -305,17 +305,84 @@ class SolanaChainStrategy extends BaseChainStrategy {
305305
}
306306
}
307307

308-
// Strategy Factory
308+
class AptosChainStrategy extends BaseChainStrategy {
309+
private static readonly REQUIRED_FIELDS = {
310+
tokenAdminRegistry: (config: ChainsConfig[string]) => !config.tokenAdminRegistry?.address,
311+
mcms: (config: ChainsConfig[string]) => !config.mcms?.address,
312+
} as const
313+
314+
validateChainData(
315+
chainId: number | string | undefined,
316+
networkId: string,
317+
chainConfig: ChainsConfig[string],
318+
selectorEntry?: { selector: string; name: string },
319+
supportedChain?: SupportedChain
320+
): {
321+
isValid: boolean
322+
missingFields: string[]
323+
validatedData?: ChainDetails
324+
} {
325+
const baseValidation = this.validateBaseFields(chainId, networkId, chainConfig, selectorEntry, supportedChain)
326+
327+
if (!baseValidation.isValid || !baseValidation.baseData) {
328+
return {
329+
isValid: false,
330+
missingFields: baseValidation.missingFields,
331+
}
332+
}
333+
334+
const missingFields = this.validateAptosRequirements(chainConfig)
335+
336+
if (missingFields.length > 0) {
337+
logger.warn({
338+
message: "Aptos chain configuration incomplete",
339+
requestId: this.requestId,
340+
networkId,
341+
missingFields,
342+
})
343+
344+
return {
345+
isValid: false,
346+
missingFields,
347+
}
348+
}
349+
350+
const validatedData: ChainDetails = {
351+
...(baseValidation.baseData as ChainDetails),
352+
tokenAdminRegistry: chainConfig.tokenAdminRegistry?.address ?? "",
353+
mcms: chainConfig.mcms?.address ?? "",
354+
}
355+
356+
return {
357+
isValid: true,
358+
missingFields: [],
359+
validatedData,
360+
}
361+
}
362+
363+
private validateAptosRequirements(chainConfig: ChainsConfig[string]): string[] {
364+
return Object.entries(AptosChainStrategy.REQUIRED_FIELDS)
365+
.filter(([_, validator]) => validator(chainConfig))
366+
.map(([field]) => field)
367+
}
368+
}
369+
309370
class ChainStrategyFactory {
371+
private static readonly strategies = new Map<ChainType, new (requestId: string) => IChainProcessingStrategy>([
372+
["evm", EvmChainStrategy],
373+
["solana", SolanaChainStrategy],
374+
["aptos", AptosChainStrategy],
375+
])
376+
310377
static getStrategy(chainType: ChainType, requestId: string): IChainProcessingStrategy {
311-
switch (chainType) {
312-
case "evm":
313-
return new EvmChainStrategy(requestId)
314-
case "solana":
315-
return new SolanaChainStrategy(requestId)
316-
default:
317-
throw new Error(`Unsupported chain type: ${chainType}`)
378+
const StrategyClass = this.strategies.get(chainType)
379+
380+
if (!StrategyClass) {
381+
const supportedTypes = Array.from(this.strategies.keys()).join(", ")
382+
throw new Error(`Chain type "${chainType}" not supported. Available strategies: ${supportedTypes}`)
318383
}
384+
385+
return new StrategyClass(requestId)
319386
}
320387
}
321388

src/pages/api/services/token-data.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
import { Version } from "@config/data/ccip/types.ts"
1111
import { SupportedChain } from "@config/index.ts"
1212
import { getAllSupportedTokens, getAllTokenLanes, getTokenData } from "@config/data/ccip/data.ts"
13-
import { resolveChainOrThrow } from "@api/ccip/utils.ts"
13+
import { resolveChainOrThrow, generateChainKey } from "@api/ccip/utils.ts"
1414
import { logger } from "@lib/logging/index.js"
1515
import { getChainId, getChainTypeAndFamily, getTitle } from "../../../features/utils/index.ts"
1616
import { getSelectorEntry } from "@config/data/ccip/selectors.ts"
@@ -134,17 +134,17 @@ export class TokenDataService {
134134
.map((destChainId) => {
135135
const destSupportedChain = resolveChainOrThrow(destChainId)
136136
const destNumericChainId = getChainId(destSupportedChain)
137-
const { chainType } = getChainTypeAndFamily(destSupportedChain)
137+
const { chainType: destChainType } = getChainTypeAndFamily(destSupportedChain)
138138

139139
if (!destNumericChainId) return destChainId
140140

141141
if (outputKey === "chainId") {
142-
return destNumericChainId.toString()
142+
return generateChainKey(destNumericChainId, destChainType, outputKey)
143143
} else if (outputKey === "selector") {
144-
const selectorEntry = getSelectorEntry(destNumericChainId, chainType)
144+
const selectorEntry = getSelectorEntry(destNumericChainId, destChainType)
145145
return selectorEntry?.selector || destChainId
146146
} else if (outputKey === "internalId") {
147-
const selectorEntry = getSelectorEntry(destNumericChainId, chainType)
147+
const selectorEntry = getSelectorEntry(destNumericChainId, destChainType)
148148
return selectorEntry?.name || destChainId
149149
}
150150
return destChainId
@@ -154,7 +154,7 @@ export class TokenDataService {
154154
// Get the appropriate key based on outputKey parameter
155155
let chainKey = chainId
156156
if (outputKey === "chainId") {
157-
chainKey = numericChainId.toString()
157+
chainKey = generateChainKey(numericChainId, chainType, outputKey)
158158
} else if (outputKey === "selector") {
159159
const selectorEntry = getSelectorEntry(numericChainId, chainType)
160160
if (selectorEntry) {

0 commit comments

Comments
 (0)