-
Notifications
You must be signed in to change notification settings - Fork 0
[FEAT] API Data integration #183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Reviewed latest commit (fix: typecheck). Clean fix that adds
Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
| const formatRateLimit = (value: string | null) => { | ||
| if (!value || value === "0") return "0" | ||
| // Convert from wei to tokens (divide by 1e18) | ||
| const numValue = BigInt(value) | ||
| const formatted = Number(numValue) / 1e18 | ||
| return formatted.toLocaleString(undefined, { maximumFractionDigits: 2 }) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The formatRateLimit function hardcodes division by 1e18, assuming all tokens have 18 decimals. This will display incorrect values for tokens like USDC (6 decimals), USDT (6 decimals), or WBTC (8 decimals). For example, a USDC rate limit of 1000000 (1 USDC) would display as 0.000000000001 instead of 1. Consider passing the token's decimals and using 10 ** decimals for the conversion.
Fix it with Roo Code or mention @roomote and request a fix.
| useEffect(() => { | ||
| const fetchAllRateLimits = async () => { | ||
| const realtimeService = new RealtimeDataService() | ||
| const newRateLimits: Record<string, Record<string, TokenRateLimits>> = {} | ||
|
|
||
| for (const destinationChain of Object.keys(destinationLanes)) { | ||
| const source = activeTab === "outbound" ? network.key : destinationChain | ||
| const destination = activeTab === "outbound" ? destinationChain : network.key | ||
| const laneKey = `${source}-${destination}` | ||
|
|
||
| const response = await realtimeService.getLaneSupportedTokens(source, destination, environment) | ||
| if (response?.data) { | ||
| newRateLimits[laneKey] = response.data | ||
| } | ||
| } | ||
|
|
||
| setRateLimits(newRateLimits) | ||
| } | ||
|
|
||
| fetchAllRateLimits() | ||
| }, [network.key, destinationLanes, environment, activeTab]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This useEffect runs when activeTab changes, including when it becomes "verifiers". Since activeTab === "outbound" is false for the verifiers tab, the logic treats it as "inbound" and makes unnecessary API calls. Consider adding an early return when activeTab === "verifiers" to avoid fetching rate limits data that won't be displayed.
Fix it with Roo Code or mention @roomote and request a fix.
Zelig880
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more generic comment, it does not seem like we are handling Failure of the APi request well. We log the issue, but the UI does not seem to have a "error" and may default to a value like 0 while it is incorrect.
| setIsLoadingRateLimits(false) | ||
| } | ||
|
|
||
| fetchRateLimits() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are not cleaning up the Fetch Request. This is going to results in many fetch possibly being run at the same time.
| // Get standard and FTF rate limits | ||
| const allLimits = tokenRateLimits | ||
| ? realtimeService.getAllRateLimitsForDirection(tokenRateLimits, direction) | ||
| : { standard: null, ftf: null } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are in control of the "getAllRateLimitsForDirection" so we should just return the default or whatever we want to simplify the code below. we should not have to know the "structure" to default it to null here.
| {isLoadingRateLimits ? ( | ||
| "Loading..." | ||
| ) : allLimits.standard ? ( | ||
| allLimits.standard.isEnabled ? ( | ||
| formatRateLimit(allLimits.standard.capacity) | ||
| ) : ( | ||
| "Disabled" | ||
| ) | ||
| ) : ( | ||
| <span style={{ display: "inline-flex", alignItems: "center", gap: "4px" }}> | ||
| Unavailable | ||
| <Tooltip | ||
| label="" | ||
| tip="Rate limit data is currently unavailable. You can find the Token Pool rate limit by reading the Token Pool contract directly on the relevant blockchain." | ||
| style={{ | ||
| display: "inline-block", | ||
| verticalAlign: "middle", | ||
| }} | ||
| /> | ||
| </span> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these conditions should not happen in the UI. Please abstruct it.. If you find yourself doign an if/ifsele/else, you should abstract. It is very hard to ready
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same apply to all the i, if else present in this PR
| }) { | ||
| const [search, setSearch] = useState("") | ||
| const [inOutbound, setInOutbound] = useState<LaneFilter>(LaneFilter.Outbound) | ||
| const [activeTab, setActiveTab] = useState<"outbound" | "inbound" | "verifiers">("outbound") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why you went away from using a type, if required add a new one, but this does not seem correct
| const destination = activeTab === "outbound" ? destinationChain : network.key | ||
| const laneKey = `${source}-${destination}` | ||
|
|
||
| const response = await realtimeService.getLaneSupportedTokens(source, destination, environment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are using "await" in a for loop. This may slow things down. I wouls suggest to run all this in parallel.
| // Fetch rate limits for all lanes | ||
| useEffect(() => { | ||
| const fetchAllRateLimits = async () => { | ||
| const realtimeService = new RealtimeDataService() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apply to all useEffect, const realtimeService = new RealtimeDataService(), should NOT be initiated within the useEffect, as it iw ill result in logs of memory usage and garbage collection work for no reason.
| }, | ||
| ]} | ||
| onChange={(key) => setInOutbound(key as LaneFilter)} | ||
| onChange={(key) => setActiveTab(key as "outbound" | "inbound" | "verifiers")} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned above, please re-introduce the type
| verifiers | ||
| .filter((verifier) => { | ||
| if (!search) return true | ||
| const searchLower = search.toLowerCase() | ||
| return ( | ||
| verifier.name.toLowerCase().includes(searchLower) || | ||
| verifier.address.toLowerCase().includes(searchLower) || | ||
| verifier.type.toLowerCase().includes(searchLower) | ||
| ) | ||
| }) | ||
| .map((verifier) => ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This operation should not happen here. Make a reusable function for this!
| // Get rate limit data for this lane | ||
| const source = activeTab === "outbound" ? network.key : destinationChain | ||
| const destination = activeTab === "outbound" ? destinationChain : network.key | ||
| const laneKey = `${source}-${destination}` | ||
| const laneRateLimits = rateLimits[laneKey] | ||
| const tokenRateLimits = laneRateLimits?.[token.id] | ||
|
|
||
| return ( | ||
| <tr key={networkDetails.name} className={tokenPaused ? "ccip-table__row--paused" : ""}> | ||
| <td> | ||
| <button | ||
| type="button" | ||
| className={`ccip-table__network-name ${tokenPaused ? "ccip-table__network-name--paused" : ""}`} | ||
| onClick={() => { | ||
| drawerWidthStore.set(DrawerWidth.Wide) | ||
| drawerContentStore.set(() => ( | ||
| <LaneDrawer | ||
| environment={environment} | ||
| lane={laneData} | ||
| sourceNetwork={network} | ||
| destinationNetwork={{ | ||
| name: networkDetails?.name || "", | ||
| logo: networkDetails?.logo || "", | ||
| key: destinationChain, | ||
| }} | ||
| inOutbound={inOutbound} | ||
| explorer={network.explorer} | ||
| /> | ||
| )) | ||
| }} | ||
| aria-label={`View lane details for ${networkDetails?.name}`} | ||
| > | ||
| <img | ||
| src={networkDetails?.logo} | ||
| alt={`${networkDetails?.name} blockchain logo`} | ||
| className="ccip-table__logo" | ||
| /> | ||
| {networkDetails?.name} | ||
| {tokenPaused && ( | ||
| <span className="ccip-table__paused-badge" title="Transfers are currently paused"> | ||
| ⏸️ | ||
| </span> | ||
| )} | ||
| </button> | ||
| </td> | ||
| <td> | ||
| {/* TODO: Fetch rate limits from API for both inbound and outbound | ||
| GET /api/ccip/v1/lanes/by-internal-id/{source}/{destination}/supported-tokens?environment={environment} | ||
| Response will contain both standard and custom rate limits per token */} | ||
| Disabled | ||
| </td> | ||
| <td> | ||
| {/* TODO: Fetch rate limits from API for both inbound and outbound | ||
| Display refill rate from standard.in/out or custom.in/out based on inOutbound filter */} | ||
| Disabled | ||
| </td> | ||
| <td> | ||
| {inOutbound === LaneFilter.Outbound | ||
| ? determineTokenMechanism(network.tokenPoolType, destinationPoolType) | ||
| : determineTokenMechanism(destinationPoolType, network.tokenPoolType)} | ||
| </td> | ||
| {/* <td> | ||
| const realtimeService = new RealtimeDataService() | ||
| const direction = activeTab === "outbound" ? "out" : "in" | ||
|
|
||
| // Get standard and FTF rate limits | ||
| const allLimits = tokenRateLimits | ||
| ? realtimeService.getAllRateLimitsForDirection(tokenRateLimits, direction) | ||
| : { standard: null, ftf: null } | ||
|
|
||
| // Token is paused if standard rate limit capacity is 0 | ||
| const tokenPaused = allLimits.standard?.capacity === "0" | ||
|
|
||
| // Format rate limit values | ||
| const formatRateLimit = (value: string | null) => { | ||
| if (!value || value === "0") return "0" | ||
| const numValue = BigInt(value) | ||
| const formatted = Number(numValue) / 1e18 | ||
| return formatted.toLocaleString(undefined, { maximumFractionDigits: 2 }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic should not live in a the UI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, lots of this logic is the same as the other file, please abstract
| {isLoading | ||
| ? "Loading..." | ||
| : allLimits.standard | ||
| ? allLimits.standard.isEnabled | ||
| ? formatRateLimit(allLimits.standard.capacity) | ||
| : "Disabled" | ||
| : "N/A"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other occurances of If/elseif/else
- Create custom hooks for data fetching: * useTokenRateLimits - single lane rate limits * useMultiLaneRateLimits - multiple lanes in parallel * useTokenFinality - token finality data - Add RateLimitCell component to replace complex nested ternaries - Create singleton realtimeDataService instance to avoid multiple instantiations - Add rate-limit-formatter utilities for consistent formatting - Update LaneDrawer, TokenDrawer, and TokenChainsTable to use new hooks - Add proper cleanup in useEffect hooks to prevent memory leaks Benefits: - Reduced code duplication (~133 lines removed) - Improved readability with <RateLimitCell> vs 7-level nested ternaries - Better separation of concerns - More testable code - Proper cleanup handling
* feat: add verifiers to the search * refactor: simplify verifiers mapping in Chain component * refactor: simplify verifiers mapping in CCIP components * refactor: optimize token mapping for verifiers in CCIP components
Uh oh!
There was an error while loading. Please reload this page.