-
Notifications
You must be signed in to change notification settings - Fork 185
feat: add swap token component #1558
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
base: main
Are you sure you want to change the base?
Conversation
|
|
Someone is attempting to deploy a commit to the pro-components Team on Vercel. A member of the Team first needs to authorize it. |
Summary of ChangesHello @li-jianli, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers a new Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
Warning Rate limit exceeded@li-jianli has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 24 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthrough新增完整的 SwapToken 套件:包含泛型 SwapToken 主组件及子组件(CryptoInput、TokenSelector、PrimaryButton)、样式与 useStyle 钩子、类型定义、格式化工具、演示、测试,并在全局声明中加入对 Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant SwapToken
participant CryptoInput
participant TokenSelector
participant FeeCalc as onCalculateFee
participant ButtonHandler as onButtonClick
User->>SwapToken: 输入值 / 切换代币 / 点击 Max
SwapToken->>CryptoInput: 设置/验证 valueIn 并传递状态
SwapToken->>TokenSelector: 渲染或切换 token
alt 需要估算费用
SwapToken->>FeeCalc: 调用 onCalculateFee(valueIn, tokenPair)
FeeCalc-->>SwapToken: 返回 estFee / estFeeRate
SwapToken->>CryptoInput: 更新 valueOut(或基于 calculateValueOut)
end
User->>SwapToken: 点击 Swap 按钮
SwapToken->>ButtonHandler: 调用 onButtonClick({ tokenPair, valueIn, valueOut })
ButtonHandler-->>SwapToken: 异步返回结果
SwapToken-->>User: 更新加载 / 成功 / 错误 状态
Estimated code review effort🎯 4 (复杂) | ⏱️ ~60 分钟 需要重点关注:
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 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.
Code Review
This pull request introduces a new SwapToken component, which is a significant feature addition. The implementation is comprehensive, covering token selection, input validation, and transaction simulation. My review focuses on improving code quality and maintainability. Key suggestions include removing leftover console.log statements, refactoring duplicated and overly complex logic into smaller functions, and addressing issues with React hooks like missing dependencies in useCallback. I've also pointed out some dead code and CSS practices that could be improved. Overall, this is a solid contribution, and addressing these points will make the new component more robust and easier to maintain.
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.
Actionable comments posted: 13
🧹 Nitpick comments (10)
packages/web3/src/swap-token/demos/fee-control.tsx (1)
62-72: 建议使用设计令牌替代硬编码颜色硬编码的颜色值
#666可能与 Ant Design 主题不一致。建议使用设计令牌以确保在不同主题下的一致性。- color: '#666', + color: 'var(--ant-color-text-secondary)',基于 learnings,样式实现应使用 Ant Design 的 Design Tokens。
packages/web3/src/swap-token/__tests__/basic.test.tsx (2)
73-82: 建议使用 data-testid 替代 CSS 类选择器使用 CSS 类选择器
.ant-web3-swap-token-swap-icon进行元素查询较为脆弱,可能因样式重构而失效。建议在组件中添加data-testid属性以提高测试稳定性。- const swapIcon = container.querySelector('.ant-web3-swap-token-swap-icon'); - expect(swapIcon).toBeTruthy(); - fireEvent.click(swapIcon as Element); + const swapIcon = screen.getByTestId('swap-icon'); + fireEvent.click(swapIcon);注意:这需要在 SwapToken 组件的 swap icon 容器上添加相应的
data-testid="swap-icon"属性。
84-102: 建议补充更多测试场景当前测试覆盖了基本功能,建议考虑添加以下测试用例以提高覆盖率:
onValueOutChange回调测试switchToken代币切换功能测试- 边界值输入测试(如空值、负数、超大数值)
需要我帮助生成这些额外的测试用例吗?
packages/web3/src/swap-token/demos/mockData.tsx (1)
9-26: 演示用TokenBadge建议抽成可复用的小组件(可选)这里在 mockData 里直接定义了一个带内联样式的
TokenBadge,用作多个代币的icon:const TokenBadge: React.FC<TokenBadgeProps> = ({ text, background }) => ( <span style={{ ... }}>{text}</span> );目前只在 demo 中使用完全没问题,不过如果后面其它 demo 也会复用类似标记器,建议:
- 抽到
demos/components/TokenBadge.tsx之类的公共演示组件;- 或至少把样式对象提到组件外部常量,避免每次渲染都新建对象。
纯属可读性/复用层面的优化,不影响当前功能。
packages/web3/src/swap-token/demos/quota.tsx (1)
21-59: 配额 demo 逻辑合理,switchToken可加注释说明意图(可选)整体交互(方向切换、手续费 loading、
maxInputAmount/quota配置等)都符合文档描述,作为示例够用。这里:
tokens={[quotaToken]} token={quotaToken} switchToken={() => {}}因为只有一个 token 组合,
switchToken做成空函数是可以的,但对阅读者不太直观。可以考虑:
- 在上方加一行注释说明“本示例仅支持一个交易对,因此切换无效”;或
- 直接省略
switchToken,如果组件实现里允许该属性为可选的话。纯改进可读性的建议,非必改。
packages/web3/src/swap-token/style/index.tsx (1)
82-113: Use Design Tokens instead of hardcoded colors in shadow definitionsThe shadow definitions contain hardcoded color values:
boxShadow: '0 1px 1px 0 rgba(0, 0, 0, 2%)'boxShadow: '0 0 10px 0 rgba(0, 0, 0, 10%)'Per the styling guidelines, these should utilize Ant Design's Design Tokens for custom styling support rather than hardcoded values. Consider using shadow-related tokens or defining custom tokens for shadow opacity to ensure consistency with the design system and support for theme customization.
packages/web3/src/swap-token/PrimaryButton/style/index.tsx (1)
14-24: 考虑将硬编码颜色值提取为 Design Tokens。渐变背景和边框颜色(如
#676767、#4d6aff、#494848等)目前是硬编码的。为了更好的主题化支持和一致性,可以考虑将这些颜色值提取为 Design Tokens 或组件级别的 token 变量。packages/web3/src/swap-token/CryptoInput.tsx (2)
114-136:statususeMemo 缺少isGreaterThanGlobalRemainQuota函数依赖。
isGreaterThanGlobalRemainQuota函数在 useMemo 内部被调用,但该函数依赖于isValidMaxInputAmount、quota?.show、remainQuota和token?.decimals。虽然remainQuota已在依赖数组中,但为了确保正确性,建议将该函数移入 useMemo 内部或使用 useCallback 包装。
170-176: 自动聚焦使用 setTimeout 可能导致竞态条件。当
edit快速切换时,setTimeout 可能在组件卸载后执行。建议添加清理函数。React.useEffect(() => { if (edit) { - setTimeout(() => { - inputRef.current?.focus(); - }, 100); + const timer = setTimeout(() => { + inputRef.current?.focus(); + }, 100); + return () => clearTimeout(timer); } }, [edit]);packages/web3/src/swap-token/TokenSelector.tsx (1)
40-91: 为组件添加 displayName 以便于调试。当前默认导出是匿名箭头函数,在 React DevTools 中会显示为
Anonymous。建议为组件命名以便调试。-export default <T,>({ +const TokenSelector = <T,>({ tokens, token, switchToken, fundFlowDirection, disabled = false, customizePrefixCls = CUSTOMIZE_PREFIX_CLS, hashId = '', -}: TokenSelectorProps<T>) => { +}: TokenSelectorProps<T>) => { // ... component body }; + +export default TokenSelector;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
packages/web3/src/swap-token/icons/swapBg.pngis excluded by!**/*.pngpackages/web3/src/swap-token/icons/swapBgNoAccount.pngis excluded by!**/*.png
📒 Files selected for processing (18)
packages/web3/global.d.ts(1 hunks)packages/web3/src/index.ts(1 hunks)packages/web3/src/swap-token/CryptoInput.tsx(1 hunks)packages/web3/src/swap-token/PrimaryButton/index.tsx(1 hunks)packages/web3/src/swap-token/PrimaryButton/style/index.tsx(1 hunks)packages/web3/src/swap-token/TokenSelector.tsx(1 hunks)packages/web3/src/swap-token/__tests__/basic.test.tsx(1 hunks)packages/web3/src/swap-token/constant.ts(1 hunks)packages/web3/src/swap-token/demos/basic.tsx(1 hunks)packages/web3/src/swap-token/demos/fee-control.tsx(1 hunks)packages/web3/src/swap-token/demos/mockData.tsx(1 hunks)packages/web3/src/swap-token/demos/quota.tsx(1 hunks)packages/web3/src/swap-token/index.md(1 hunks)packages/web3/src/swap-token/index.tsx(1 hunks)packages/web3/src/swap-token/index.zh-CN.md(1 hunks)packages/web3/src/swap-token/style/index.tsx(1 hunks)packages/web3/src/swap-token/type.ts(1 hunks)packages/web3/src/swap-token/utils/format.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/__tests__/**
📄 CodeRabbit inference engine (.cursor/rules/basic.mdc)
**/__tests__/**: Unit tests should be based on Vitest framework
Test code should be located in the__tests__folder
Files:
packages/web3/src/swap-token/__tests__/basic.test.tsx
**/style/index.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/basic.mdc)
**/style/index.{ts,tsx}: Styles for each component should be located instyle/index.tsorstyle/index.tsxdirectory within the component's folder
Styling implementation should be based on@ant-design/cssinjsand utilize Ant Design's Design Tokens for custom styling support
Files:
packages/web3/src/swap-token/style/index.tsxpackages/web3/src/swap-token/PrimaryButton/style/index.tsx
🧠 Learnings (6)
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: This is a multi-package React project built on Ant Design component library, designed to provide Web3 projects with wallet connection capabilities and DApp UI components
Applied to files:
packages/web3/src/swap-token/__tests__/basic.test.tsxpackages/web3/src/swap-token/demos/quota.tsxpackages/web3/src/swap-token/demos/mockData.tsxpackages/web3/src/swap-token/PrimaryButton/index.tsxpackages/web3/src/swap-token/index.mdpackages/web3/src/swap-token/CryptoInput.tsxpackages/web3/src/index.tspackages/web3/src/swap-token/demos/basic.tsxpackages/web3/src/swap-token/index.tsxpackages/web3/src/swap-token/demos/fee-control.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: Applies to **/style/index.{ts,tsx} : Styling implementation should be based on `ant-design/cssinjs` and utilize Ant Design's Design Tokens for custom styling support
Applied to files:
packages/web3/src/swap-token/PrimaryButton/index.tsxpackages/web3/src/swap-token/style/index.tsxpackages/web3/src/index.tspackages/web3/src/swap-token/demos/basic.tsxpackages/web3/src/swap-token/index.tsxpackages/web3/src/swap-token/PrimaryButton/style/index.tsxpackages/web3/src/swap-token/TokenSelector.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: Applies to packages/web3/*/index.{md,zh-CN.md} : Documentation files should be available as `packages/web3/*/index.md` and `packages/web3/*/index.zh-CN.md` for component documentation and `packages/web3/ethereum` for wagmi package documentation
Applied to files:
packages/web3/src/swap-token/index.mdpackages/web3/src/swap-token/index.zh-CN.md
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: Applies to **/style/index.{ts,tsx} : Styles for each component should be located in `style/index.ts` or `style/index.tsx` directory within the component's folder
Applied to files:
packages/web3/src/swap-token/style/index.tsxpackages/web3/src/swap-token/PrimaryButton/style/index.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: UI components are located under `packages/web3`, with other packages containing adapters for different blockchains or foundational packages
Applied to files:
packages/web3/src/index.ts
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: Applies to packages/web3/*/demos/** : Demo components should be located in `packages/web3/*/demos` directories
Applied to files:
packages/web3/src/swap-token/demos/basic.tsx
🧬 Code graph analysis (9)
packages/web3/src/swap-token/demos/quota.tsx (1)
packages/web3/src/swap-token/demos/mockData.tsx (1)
mockTokenPairs(32-77)
packages/web3/src/swap-token/demos/mockData.tsx (2)
packages/web3/src/index.ts (2)
SwapTokenConfig(15-15)SwapTokenToken(16-16)packages/web3/src/swap-token/style/index.tsx (1)
SwapTokenToken(8-11)
packages/web3/src/swap-token/PrimaryButton/index.tsx (2)
packages/web3/src/swap-token/PrimaryButton/style/index.tsx (1)
useStyle(52-60)packages/web3/src/swap-token/style/index.tsx (1)
useStyle(191-199)
packages/web3/src/swap-token/CryptoInput.tsx (6)
packages/web3/src/swap-token/TokenSelector.tsx (2)
T(40-91)TokenSelectorProps(8-23)packages/web3/src/swap-token/index.tsx (2)
Token(437-437)TokenConfig(437-437)packages/web3/src/swap-token/type.ts (2)
Token(1-19)TokenConfig(24-36)packages/web3/src/swap-token/constant.ts (3)
CUSTOMIZE_PREFIX_CLS(7-7)TOKEN_DECIMALS_DEFAULT(2-2)AMOUNT_IN_DECIMALS(4-4)packages/web3/src/index.ts (1)
FundFlowDirection(18-18)packages/web3/src/swap-token/utils/format.ts (3)
formatAmount(70-82)formatValue(42-63)formatBalance(10-20)
packages/web3/src/swap-token/style/index.tsx (3)
packages/web3/src/index.ts (1)
SwapTokenToken(16-16)packages/web3/src/theme/useStyle/index.ts (3)
Web3AliasToken(45-64)GenerateStyle(35-38)UseStyleResult(40-43)packages/web3/src/swap-token/PrimaryButton/style/index.tsx (1)
useStyle(52-60)
packages/web3/src/swap-token/demos/basic.tsx (2)
packages/web3/src/swap-token/demos/mockData.tsx (1)
mockTokenPairs(32-77)packages/web3/src/index.ts (1)
FundFlowDirection(18-18)
packages/web3/src/swap-token/PrimaryButton/style/index.tsx (2)
packages/web3/src/theme/useStyle/index.ts (2)
GenerateStyle(35-38)UseStyleResult(40-43)packages/web3/src/swap-token/style/index.tsx (1)
useStyle(191-199)
packages/web3/src/swap-token/demos/fee-control.tsx (2)
packages/web3/src/swap-token/demos/mockData.tsx (1)
mockTokenPairs(32-77)packages/web3/src/index.ts (1)
FundFlowDirection(18-18)
packages/web3/src/swap-token/TokenSelector.tsx (3)
packages/web3/src/swap-token/type.ts (2)
TokenConfig(24-36)Token(1-19)packages/web3/src/index.ts (1)
FundFlowDirection(18-18)packages/web3/src/swap-token/constant.ts (1)
CUSTOMIZE_PREFIX_CLS(7-7)
🪛 LanguageTool
packages/web3/src/swap-token/index.md
[style] ~42-~42: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...lance area of the upper / lower input | { upper?: (balance?: SwapTokenToken<T>, token?: SwapTokenConfig<T, SwapTokenToken<T>>) => React.ReactNode; under?: (balance?: SwapTokenToken<T>, token?: SwapTokenConfig<T, SwapTokenToken<T>>) => React.ReactNode } | - | - | | underButtonRender | Rend...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
packages/web3/src/swap-token/index.zh-CN.md
[grammar] ~12-~12: Ensure spelling is correct
Context: ...CryptoInput、代币选择器以及操作按钮的兑换面板,适合在 DApp 中快速集成。尤其适合跨链兑换业务中。 ## 基础用法 </co...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[style] ~41-~41: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... | | extraRenders | 自定义上下两组输入框右侧区域的渲染 | { upper?: (balance?: SwapTokenToken<T>, token?: SwapTokenConfig<T, SwapTokenToken<T>>) => React.ReactNode; under?: (balance?: SwapTokenToken<T>, token?: SwapTokenConfig<T, SwapTokenToken<T>>) => React.ReactNode } | - | - | | underButtonRender | 主按钮下...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: prepare preview
- GitHub Check: ci
🔇 Additional comments (13)
packages/web3/global.d.ts (1)
13-17: LGTM!
PNG 模块声明符合 TypeScript 资源导入的标准模式,导出类型为 string(URL)是处理图片资源的正确方式,与现有的 SVG 声明保持一致的风格。
packages/web3/src/swap-token/type.ts (1)
21-47: 类型设计合理
TokenConfig 接口和 FundFlowDirection 枚举的设计清晰,支持成对的代币配置和资金流向控制。条件类型 T extends string ? (string extends T ? never : T) : never 有效地强制使用字面量字符串类型,这是一个很好的类型安全实践。
packages/web3/src/index.ts (1)
11-18: LGTM!
SwapToken 组件和相关类型的导出方式与文件中其他组件的导出模式保持一致。类型导出使用 SwapToken 前缀(如 SwapTokenConfig、SwapTokenToken)有助于避免命名冲突,符合库的命名规范。
packages/web3/src/swap-token/demos/fee-control.tsx (1)
16-58: LGTM!
Demo 组件结构清晰,很好地展示了 SwapToken 的 API 用法,包括代币选择、资金流向切换、额外描述信息渲染以及数值变更回调等功能。
packages/web3/src/swap-token/__tests__/basic.test.tsx (1)
52-71: LGTM!
测试用例使用了正确的 Vitest 框架和 Testing Library 最佳实践,包括 vi.waitFor 进行异步断言和 vi.fn().mockResolvedValue() 进行 mock。符合编码规范中对单元测试的要求。
packages/web3/src/swap-token/demos/basic.tsx (1)
8-52: 基础用法 demo 逻辑清晰,没有明显问题
selectedToken / direction 状态管理简单直观;
switchToken 对 undefined 做了降级处理,避免内部回调传空值时崩溃;
extra 与 underButtonRender 的展示字段也与 mock 数据结构对应。
整体作为文档示例已经足够,当前实现可以保持。
packages/web3/src/swap-token/index.zh-CN.md (1)
10-89: 中文文档与 API 定义基本一致
阅读下来,SwapToken 的属性、SwapTokenConfig / SwapTokenToken / FundFlowDirection 等说明都与英文文档及类型定义对得上,目前没有看到名称、类型或默认值上的偏差。
如果后续实现侧对某些默认值(例如 btnText、title、showConnectButton 等)有调整,记得同步更新此表即可。
packages/web3/src/swap-token/index.md (1)
11-90: 英文文档与实现/中文文档对齐良好
SwapToken、SwapTokenConfig、SwapTokenToken 以及 FundFlowDirection 各表格字段、类型和默认值与中文文档及组件行为一致,描述也比较清楚,没有明显歧义或遗漏。
目前可以按这个版本收录到站点,如后续 API 有新增/重命名,再一起补充即可。
packages/web3/src/swap-token/PrimaryButton/style/index.tsx (1)
1-59: 样式模块结构符合规范。
样式实现正确地基于 @ant-design/cssinjs,并使用了 Ant Design 的 Design Tokens(如 borderRadiusLG、colorWhite)。组件命名 SwapTokenPrimaryButton 和前缀类的使用与项目中其他样式模块保持一致。
packages/web3/src/swap-token/utils/format.ts (1)
84-96: decimalToBigInt 的 fallback 逻辑设计合理。
使用 viem 的 parseUnits 作为主要实现,并在失败时回退到 Decimal.js 是一个稳健的设计。
packages/web3/src/swap-token/index.tsx (2)
97-435: 组件整体结构清晰,使用 forwardRef 暴露 reset 方法的设计合理。
主要功能包括双向输入、手续费计算、代币切换和交换方向切换,与其他子组件(CryptoInput、TokenSelector、PrimaryButton)的集成良好。
437-437: 缺少 FundFlowDirection 的类型导出。
根据 AI 摘要,FundFlowDirection 应该从该模块导出,但当前只导出了 Token 和 TokenConfig 类型。请验证该类型在 ./type 文件中的定义和导出状态。
packages/web3/src/swap-token/TokenSelector.tsx (1)
52-61: Handle potential undefined optionToken in options mapping.
The code selects between fromToken and toToken based on fundFlowDirection, but if either field is optional in TokenConfig, optionToken could be undefined when passed to renderTokenLabel. Either validate that the selected field exists before calling renderTokenLabel, or ensure the function handles undefined safely.
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.
Actionable comments posted: 0
♻️ Duplicate comments (6)
packages/web3/src/swap-token/index.tsx (3)
159-167: 移除注释掉的代码。大段注释代码会影响可读性和维护性。如果这些代码不再需要,应该删除;如果是待实现的功能,建议用简洁的 TODO 注释说明并引用 issue。
应用以下修改:
}, [fundFlowDirection, token]); - // const invalidInput = React.useMemo(() => { - // const tokenIn = tokenInfo?.find( - // (item) => item?.symbol === tokenPair[0]?.symbol, - // ); - - // const amount = formatAmount({amount: valueIn, decimals: tokenIn?.decimals}) - - // return buttonDisabled || amount.eq(0) || status === 'error'; - // }, [buttonDisabled, valueIn, tokenInfo, tokenPair, status]); - const invalidInput = React.useMemo(() => {
295-299: useEffect 依赖数组不完整。
handleCalculateFee和valueIn在 effect 中被使用但未声明为依赖。由于handleCalculateFee不是用useCallback包装的,每次渲染都会创建新函数,可能导致问题。在将
handleCalculateFee包裹在useCallback后,应用以下修改:React.useEffect(() => { if (!token) return; // token发生变化时,重新计算手续费 handleCalculateFee(valueIn); - }, [token]); + }, [token, handleCalculateFee, valueIn]);注意:如果只希望在 token 变化时触发,可以保持当前依赖数组,但需要确保
handleCalculateFee使用最新的valueIn值(例如通过 ref)。
266-278: 修复handleSwapClick中的重复状态重置。
setButtonLoading(false)在 catch 块和函数末尾都被调用,导致在正常流程和错误流程中都会执行。应使用finally块确保只执行一次。应用以下修改:
const handleSwapClick = async () => { setButtonLoading(true); try { if (status === 'error') { message.error('Invalid input'); } else { await onButtonClick?.(tokenPair, valueIn, valueOut); } } catch (error) { + console.error('Swap error:', error); + } finally { setButtonLoading(false); } - setButtonLoading(false); };packages/web3/src/swap-token/CryptoInput.tsx (3)
138-144: useEffect 缺少依赖项onStatusChange。根据 React Hooks 规则,
onStatusChange应该包含在依赖数组中。如果该回调可能变化,当前代码可能导致使用过期的回调引用。应用以下修改:
React.useEffect(() => { if (status === 'error') { onStatusChange?.('error'); } else { onStatusChange?.('success'); } - }, [status]); + }, [status, onStatusChange]);注意:如果
onStatusChange在每次渲染时都会重新创建,请在声明处使用useCallback包裹以避免不必要的重新渲染。
185-188: useEffect 缺少依赖项onChangeValue。
onChangeValue被使用但未在依赖数组中声明。应用以下修改:
React.useEffect(() => { if (!!status) return; onChangeValue?.(inputValue); - }, [inputValue, status]); + }, [inputValue, status, onChangeValue]);如果
onChangeValue在每次渲染时都会重新创建,建议在其声明处使用useCallback包裹,或在 effect 内部通过 ref 稳定引用。
367-369:Decimal构造函数不接受bigint类型。
remainQuota是bigint类型,但Decimal()构造函数不直接支持bigint。应先转换为字符串。应用以下修改:
{formatAmount({ amount: inputValue, decimals: token?.decimals }).gt( - Decimal(remainQuota || 0n), + Decimal((remainQuota || 0n).toString()), ) && (
🧹 Nitpick comments (4)
packages/web3/src/swap-token/CryptoInput.tsx (2)
94-165: 提取公共验证逻辑以减少代码重复。
isGreaterThanGlobalRemainQuota和isGreaterThanMaxAmount两个函数共享了大量相似的验证逻辑(长度检查、正则验证、Decimal 转换)。此外,正则验证是多余的,因为Decimal转换已经包裹在try...catch中,会自动处理无效的数字格式。建议提取公共验证逻辑到一个辅助函数中:
+const validateAndConvertToDecimal = ( + value: string, + decimals?: number +): Decimal | null => { + if (!value?.length) return null; + try { + const result = Decimal(value?.replace(/,/g, '') ?? '0').mul( + Decimal.pow(10, decimals ?? TOKEN_DECIMALS_DEFAULT), + ); + return result; + } catch (error) { + return null; + } +}; + const isGreaterThanGlobalRemainQuota = (value: string) => { if (!isValidMaxInputAmount) return false; - try { - if (!value?.length) return false; - if (!quota?.show) return false; - // 验证是否是合法的 Decimal:允许整数、小数和千位分隔符,小数位中不能有千位分隔符 - const regex = /^(\d{1,3}(,\d{3})*|\d+)(.\d+)?$/; - if (!regex.test(value?.replace(/,/g, ''))) { - return false; - } - if (!remainQuota || remainQuota === 0n) return true; - const result = Decimal(value?.replace(/,/g, '') ?? '0').mul( - Decimal.pow(10, token?.decimals ?? TOKEN_DECIMALS_DEFAULT), - ); - return result.gt(remainQuota); - } catch (error) { - return false; - } + if (!quota?.show) return false; + if (!remainQuota || remainQuota === 0n) return true; + const result = validateAndConvertToDecimal(value, token?.decimals); + return result ? result.gt(remainQuota.toString()) : false; }; const isGreaterThanMaxAmount = (value: string) => { if (!isValidMaxInputAmount) return false; - try { - if (!value?.length) return false; - - // 验证是否是合法的 Decimal:允许整数、小数和千位分隔符,小数位中不能有千位分隔符 - const regex = /^(\d{1,3}(,\d{3})*|\d+)(.\d+)?$/; - if (!regex.test(value?.replace(/,/g, ''))) { - return false; - } - if (!maxInputAmountValue) return false; - const result = Decimal(value?.replace(/,/g, '') ?? '0').mul( - Decimal.pow(10, token?.decimals ?? TOKEN_DECIMALS_DEFAULT), - ); - return result.gt(maxInputAmountValue); - } catch (error) { - return false; - } + if (!maxInputAmountValue) return false; + const result = validateAndConvertToDecimal(value, token?.decimals); + return result ? result.gt(maxInputAmountValue.toString()) : false; };
265-330: 考虑重构复杂的 onChange 处理逻辑。这个
onChange事件处理器包含了大量复杂的输入验证和格式化逻辑(约 65 行)。为了提升可读性和可维护性,建议将其拆分为命名清晰的辅助函数,例如:
handleDecimalPoint- 处理小数点输入handleLeadingZeros- 处理前导零handleDecimalPrecision- 限制小数位数clampToMaxValue- 处理最大值约束示例重构:
const handleDecimalPoint = (value: string) => { if (value === '.') return '0.'; if (value.split('.').length > 2) return inputValue ?? ''; return value; }; const sanitizeInput = (value: string) => { const newValue = value.replace(/[^\d,.]/g, ''); return newValue.length === value.length ? newValue : inputValue ?? ''; }; // 在 onChange 中使用这些辅助函数 onChange={(e) => { const sanitized = sanitizeInput(e.target.value); const withDecimal = handleDecimalPoint(sanitized); // ... 其他验证逻辑 }}packages/web3/src/swap-token/index.tsx (2)
222-256: 将handleValueOutChange包裹在useCallback中以优化性能。该函数作为 prop 传递给
CryptoInput组件,但在每次渲染时都会重新创建,导致子组件不必要的重新渲染。应用以下修改:
- const handleValueOutChange = (value: string) => { + const handleValueOutChange = useCallback((value: string) => { if (value && !/[^\d,.]/g.test(value)) { if (['', ',', '.'].includes(value)) { setValueIn(''); return; } try { const valueOutWithoutComma = value?.replace(/,/g, '') ?? ''; if (Decimal(valueOutWithoutComma).eq(0) && value?.match(/^[\d.]+$/)) { setValueIn('0.00'); return; } // 自定义计算 if (calculateValueIn) { const valueIn = calculateValueIn( decimalToBigInt(valueOutWithoutComma, token?.decimals || 0), ); if (Decimal(valueIn).lte(0)) { setValueIn('0.00'); return; } setValueIn(formatValue(Decimal(valueIn).toFixed()) ?? '0.00'); return; } // valueIn = valueOut + 跨链桥费用(按目标币种精度) const networkFee = Decimal(estFee).div(Decimal(10).pow(Decimal(token?.decimals || 0))); const inVal = Decimal(valueOutWithoutComma).add(networkFee); setValueIn(formatValue(inVal.toFixed()) ?? '0.00'); } catch (error) { setValueIn('0.00'); } } else { setValueIn('0.00'); } - }; + }, [calculateValueIn, estFee, token]);
282-293: 将handleCalculateFee包裹在useCallback中。该函数在
useEffect中使用且作为 prop 传递给CryptoInput。应该包裹在useCallback中以确保其引用稳定,避免不必要的 effect 重新执行和子组件重新渲染。应用以下修改:
- const handleCalculateFee = async (valueIn?: string) => { + const handleCalculateFee = useCallback(async (valueIn?: string) => { if (!onCalculateFee || !valueIn?.length) { return; } try { setIsCalculatingFee(true); await onCalculateFee?.(valueIn); setIsCalculatingFee(false); } catch (error) { setIsCalculatingFee(false); } - }; + }, [onCalculateFee]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/web3/src/swap-token/CryptoInput.tsx(1 hunks)packages/web3/src/swap-token/index.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: This is a multi-package React project built on Ant Design component library, designed to provide Web3 projects with wallet connection capabilities and DApp UI components
Applied to files:
packages/web3/src/swap-token/CryptoInput.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: Applies to **/style/index.{ts,tsx} : Styling implementation should be based on `ant-design/cssinjs` and utilize Ant Design's Design Tokens for custom styling support
Applied to files:
packages/web3/src/swap-token/index.tsx
🧬 Code graph analysis (2)
packages/web3/src/swap-token/CryptoInput.tsx (5)
packages/web3/src/swap-token/TokenSelector.tsx (2)
T(40-91)TokenSelectorProps(8-23)packages/web3/src/swap-token/type.ts (2)
Token(1-19)TokenConfig(24-36)packages/web3/src/swap-token/constant.ts (3)
CUSTOMIZE_PREFIX_CLS(7-7)TOKEN_DECIMALS_DEFAULT(2-2)AMOUNT_IN_DECIMALS(4-4)packages/web3/src/index.ts (1)
FundFlowDirection(18-18)packages/web3/src/swap-token/utils/format.ts (2)
formatAmount(70-82)formatValue(42-63)
packages/web3/src/swap-token/index.tsx (6)
packages/web3/src/swap-token/TokenSelector.tsx (2)
T(40-91)TokenSelectorProps(8-23)packages/web3/src/swap-token/type.ts (2)
TokenConfig(24-36)Token(1-19)packages/web3/src/swap-token/constant.ts (1)
CUSTOMIZE_PREFIX_CLS(7-7)packages/web3/src/swap-token/PrimaryButton/style/index.tsx (1)
useStyle(52-60)packages/web3/src/swap-token/style/index.tsx (1)
useStyle(191-199)packages/web3/src/swap-token/utils/format.ts (2)
decimalToBigInt(85-96)formatValue(42-63)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: prepare preview
- GitHub Check: ci
🔇 Additional comments (1)
packages/web3/src/swap-token/index.tsx (1)
181-220: 好的修复!依赖数组现已完整。
handleValueInChange的useCallback依赖数组现在已经包含了所有必需的依赖项(calculateValueOut、token、onValueOutChange),之前的问题已得到解决。
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.
Actionable comments posted: 2
♻️ Duplicate comments (1)
packages/web3/src/swap-token/index.tsx (1)
269-281:handleSwapClick中重复重置 loading 且静默吞掉错误,建议用 try/catch/finally 重构当前实现中:
setButtonLoading(false)在catch和函数末尾都会被调用一次,虽然不会出大问题,但属于不必要的重复。- 捕获到异常后既不打日志也不向用户暴露任何信息,排查问题会比较困难。
建议改成:
const handleSwapClick = async () => { setButtonLoading(true); try { if (status === 'error') { message.error('Invalid input'); } else { await onButtonClick?.(tokenPair, valueIn, valueOut); } - } catch (error) { - setButtonLoading(false); - } - setButtonLoading(false); + } catch (error) { + // 可以按需换成 message.error 等用户提示 + console.error('Swap error:', error); + } finally { + setButtonLoading(false); + } };这样既避免了重复调用,又能在出错时至少留下可追踪的日志。
🧹 Nitpick comments (2)
packages/web3/src/swap-token/style/index.tsx (1)
14-188: 样式中大量硬编码颜色与固定尺寸,建议更多使用设计令牌和弹性布局当前样式虽然功能上没问题,但有不少硬编码颜色与固定像素值,例如:
- 颜色:
'#e6ecf4','#fbfcfd','#f7f8fa','#a8a8a8','#f00'等(如第 82、88、92、139、160、181、394 行附近)。- 尺寸与定位:
width: 600,left: 273,top: 198,width: '100px',height: '40px'等(如第 19、65–68、103–108 行附近)。这会削弱主题定制(深色模式、品牌色等)和响应式布局的能力。建议:
- 尽量用
Web3AliasToken/ 主题中的设计令牌(例如colorBorderSecondary,colorBgElevated,boxShadowSecondary等)替代硬编码颜色和阴影。- 对宽度和定位优先使用百分比、
maxWidth、margin/gap等,更少依赖绝对像素和 magic number 坐标,以提升在小屏下的适配性。可以先从按钮、选择器、错误提示这几处最容易暴露主题差异的区域逐步抽象。
As per coding guidelines, ...packages/web3/src/swap-token/index.tsx (1)
58-61:onCalculateFee类型与实际异步用法不一致,建议显式声明为可返回 Promise
SwapInputProps中onCalculateFee的类型是:onCalculateFee?: (valueIn?: string) => void;但在
handleCalculateFee里你是用await onCalculateFee?.(valueIn);来调用它(第 292 行),实际上是按“可能返回 Promise”来使用的。虽然在 TS 中
await任意值在类型层面是允许的,但为了让 props 的语义更清晰、更符合实际用法,建议把类型显式写成:- /** 开始预估费用 */ - onCalculateFee?: (valueIn?: string) => void; + /** 开始预估费用,可同步也可异步 */ + onCalculateFee?: (valueIn?: string) => void | Promise<void>;这样调用方就能直观知道可以返回
Promise,也更容易在 IDE 中获得正确提示。Also applies to: 283-299
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
packages/web3/src/swap-token/CryptoInput.tsx(1 hunks)packages/web3/src/swap-token/PrimaryButton/style/index.tsx(1 hunks)packages/web3/src/swap-token/constant.ts(1 hunks)packages/web3/src/swap-token/index.tsx(1 hunks)packages/web3/src/swap-token/style/index.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/web3/src/swap-token/PrimaryButton/style/index.tsx
- packages/web3/src/swap-token/constant.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/style/index.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/basic.mdc)
**/style/index.{ts,tsx}: Styles for each component should be located instyle/index.tsorstyle/index.tsxdirectory within the component's folder
Styling implementation should be based on@ant-design/cssinjsand utilize Ant Design's Design Tokens for custom styling support
Files:
packages/web3/src/swap-token/style/index.tsx
🧠 Learnings (3)
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: Applies to **/style/index.{ts,tsx} : Styling implementation should be based on `ant-design/cssinjs` and utilize Ant Design's Design Tokens for custom styling support
Applied to files:
packages/web3/src/swap-token/style/index.tsxpackages/web3/src/swap-token/index.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: Applies to **/style/index.{ts,tsx} : Styles for each component should be located in `style/index.ts` or `style/index.tsx` directory within the component's folder
Applied to files:
packages/web3/src/swap-token/style/index.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: This is a multi-package React project built on Ant Design component library, designed to provide Web3 projects with wallet connection capabilities and DApp UI components
Applied to files:
packages/web3/src/swap-token/index.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: prepare preview
- GitHub Check: ci
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.
Actionable comments posted: 0
♻️ Duplicate comments (2)
packages/web3/src/swap-token/index.tsx (2)
159-167: 移除注释代码第 159-167 行仍包含注释掉的
invalidInput计算逻辑。注释代码影响可读性,应该移除。如果这是待实现的功能,建议用简短的 TODO 注释说明或创建 issue 追踪。
302-306: useEffect 缺少 handleCalculateFee 依赖第 306 行的 useEffect 在第 305 行调用了
handleCalculateFee,但依赖数组中未包含它。虽然handleCalculateFee通过 useCallback 保持稳定,但根据 React Hooks 规则,仍应将其添加到依赖数组中。React.useEffect(() => { if (!token) return; // token发生变化时,重新计算手续费 handleCalculateFee(valueIn); - }, [token, valueIn]); + }, [token, valueIn, handleCalculateFee]);
🧹 Nitpick comments (1)
packages/web3/src/swap-token/CryptoInput.tsx (1)
215-311: 考虑提取输入验证辅助函数输入处理逻辑非常完善,涵盖了各种边界情况(小数点、千位分隔符、前导零等)。当前实现功能正确,但为了提高可维护性和可测试性,可以考虑将
normalizeDotInput、sanitizeAllowedCharacters、normalizeAllZeroInteger等辅助函数提取到独立的 utils 文件中。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
packages/web3/src/swap-token/CryptoInput.tsx(1 hunks)packages/web3/src/swap-token/PrimaryButton/index.tsx(1 hunks)packages/web3/src/swap-token/index.tsx(1 hunks)packages/web3/src/swap-token/type.ts(1 hunks)packages/web3/src/swap-token/utils/format.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/web3/src/swap-token/type.ts
- packages/web3/src/swap-token/PrimaryButton/index.tsx
- packages/web3/src/swap-token/utils/format.ts
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: This is a multi-package React project built on Ant Design component library, designed to provide Web3 projects with wallet connection capabilities and DApp UI components
Applied to files:
packages/web3/src/swap-token/index.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: Applies to **/style/index.{ts,tsx} : Styling implementation should be based on `ant-design/cssinjs` and utilize Ant Design's Design Tokens for custom styling support
Applied to files:
packages/web3/src/swap-token/index.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: UI components are located under `packages/web3`, with other packages containing adapters for different blockchains or foundational packages
Applied to files:
packages/web3/src/swap-token/index.tsx
🧬 Code graph analysis (1)
packages/web3/src/swap-token/CryptoInput.tsx (6)
packages/web3/src/swap-token/TokenSelector.tsx (2)
T(40-91)TokenSelectorProps(8-23)packages/web3/src/swap-token/index.tsx (2)
Token(396-396)TokenConfig(396-396)packages/web3/src/swap-token/type.ts (2)
Token(3-21)TokenConfig(26-38)packages/web3/src/swap-token/constant.ts (3)
CUSTOMIZE_PREFIX_CLS(7-7)AMOUNT_IN_DECIMALS(4-4)TOKEN_DECIMALS_DEFAULT(2-2)packages/web3/src/index.ts (1)
FundFlowDirection(18-18)packages/web3/src/swap-token/utils/format.ts (3)
formatAmount(70-82)formatValue(42-63)formatBalance(10-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: prepare preview
- GitHub Check: ci
🔇 Additional comments (10)
packages/web3/src/swap-token/CryptoInput.tsx (5)
1-48: 类型定义和接口设计良好导入和 Props 接口定义清晰完整,泛型 T 的使用保证了类型安全。特别是
maxInputAmount和quota的接口设计合理地处理了 bigint 类型。
130-189: bigint 类型转换已正确处理第 138 行和第 185 行现在正确地使用
Decimal(remainQuota.toString())和Decimal(maxInputAmountValue.toString())将 bigint 转换为字符串后再进行比较,避免了 Decimal.js 不支持 bigint 的问题。
144-174: 依赖数组已完善
status的 useMemo(第 166 行)和 onStatusChange 的 useEffect(第 174 行)的依赖数组现在都已完整,包含了所有使用的外部变量,避免了过时闭包问题。
209-212: useEffect 依赖数组正确第 212 行的依赖数组现在包含了
onChangeValue,确保回调变化时 effect 能正确响应。
371-472: 渲染逻辑结构清晰组件的渲染部分组织良好,条件渲染逻辑清晰,正确集成了 TokenSelector 和余额显示功能。配额提示的显示逻辑(第 415-454 行)合理地处理了全局限额的 UI 反馈。
packages/web3/src/swap-token/index.tsx (5)
181-220: useCallback 依赖数组已完善
handleValueInChange的依赖数组(第 219 行)现在包含了所有捕获的外部值:estFeeRate、estFee、token、calculateValueOut和onValueOutChange,避免了过时闭包问题。
222-259: handleValueOutChange 正确使用 useCallback该函数现在正确地使用 useCallback 包装,依赖数组包含了
estFee、token和calculateValueIn,确保了稳定的引用以避免不必要的子组件重新渲染。
269-282: 错误处理逻辑正确
handleSwapClick现在使用 try-catch-finally 模式,确保setButtonLoading(false)只在 finally 块中调用一次,并且错误被正确捕获和记录(第 278 行)。
308-393: 组件组合和渲染逻辑清晰主渲染逻辑组织良好,两个 CryptoInput 组件的配置清晰,特别是第二个 CryptoInput 正确地反转了
fundFlowDirection(第 353-357 行)并禁用了最大值校验(第 349 行),符合"现金流出"的语义。
396-398: 类型导出使用别名是良好实践使用
SwapTokenToken和SwapTokenConfig别名重新导出类型是良好的实践,避免了命名冲突并提供了更清晰的公共 API。
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.
Actionable comments posted: 0
♻️ Duplicate comments (1)
packages/web3/src/swap-token/index.tsx (1)
309-313: useEffect 依赖数组应包含handleCalculateFee。虽然此问题在过往审查中被标记为已在提交 c94235c 中解决,但当前代码中 useEffect 的依赖数组仍只包含
[token, valueIn],而实际使用了handleCalculateFee。根据 React Hooks 规则,所有在 effect 中使用的非稳定值都应声明为依赖。由于
handleCalculateFee已用useCallback包裹且仅依赖onCalculateFee,它在大多数场景下是稳定的。但如果onCalculateFee在token和valueIn未变化时发生更新,effect 将使用过期的回调。建议将
handleCalculateFee添加到依赖数组:React.useEffect(() => { if (!token) return; // token发生变化时,重新计算手续费 handleCalculateFee(valueIn); - }, [token, valueIn]); + }, [token, valueIn, handleCalculateFee]);这样可以确保在所有相关值变化时 effect 都能正确重新执行,符合 React Hooks 的最佳实践。
🧹 Nitpick comments (1)
packages/web3/src/swap-token/index.tsx (1)
162-171: 移除注释代码以提高可读性。虽然此前的审查评论标记此问题已在提交 c94235c 中解决,但代码中仍保留了注释掉的
invalidInput计算逻辑。即使是作为参考,保留注释代码也会降低代码可读性。建议完全删除这段注释,如需保留逻辑说明可改用简洁的 TODO 注释或在文档中记录。- // const invalidInput = React.useMemo(() => { - // const tokenIn = tokenInfo?.find( - // (item) => item?.symbol === tokenPair[0]?.symbol, - // ); - - // const amount = formatAmount({amount: valueIn, decimals: tokenIn?.decimals}) - - // return buttonDisabled || amount.eq(0) || status === 'error'; - // }, [buttonDisabled, valueIn, tokenInfo, tokenPair, status]); - const invalidInput = React.useMemo(() => {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
packages/web3/src/swap-token/CryptoInput.tsx(1 hunks)packages/web3/src/swap-token/PrimaryButton/index.tsx(1 hunks)packages/web3/src/swap-token/index.tsx(1 hunks)packages/web3/src/swap-token/utils/format.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/web3/src/swap-token/PrimaryButton/index.tsx
- packages/web3/src/swap-token/utils/format.ts
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: This is a multi-package React project built on Ant Design component library, designed to provide Web3 projects with wallet connection capabilities and DApp UI components
Applied to files:
packages/web3/src/swap-token/index.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: Applies to **/style/index.{ts,tsx} : Styling implementation should be based on `ant-design/cssinjs` and utilize Ant Design's Design Tokens for custom styling support
Applied to files:
packages/web3/src/swap-token/index.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: UI components are located under `packages/web3`, with other packages containing adapters for different blockchains or foundational packages
Applied to files:
packages/web3/src/swap-token/index.tsx
🧬 Code graph analysis (1)
packages/web3/src/swap-token/CryptoInput.tsx (6)
packages/web3/src/swap-token/index.tsx (2)
Token(403-403)TokenConfig(403-403)packages/web3/src/swap-token/type.ts (2)
Token(3-21)TokenConfig(26-38)packages/web3/src/crypto-input/index.tsx (1)
CryptoInput(52-183)packages/web3/src/swap-token/constant.ts (1)
CUSTOMIZE_PREFIX_CLS(7-7)packages/web3/src/index.ts (1)
FundFlowDirection(18-18)packages/web3/src/swap-token/utils/format.ts (3)
formatAmount(71-83)formatValue(43-64)formatBalance(10-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: prepare preview
- GitHub Check: ci
🔇 Additional comments (7)
packages/web3/src/swap-token/CryptoInput.tsx (4)
95-129: 输入校验逻辑完善。
isValidValue函数正确处理了整数、小数和千分位分隔符的校验,逻辑清晰且覆盖了各种边界情况。
132-191: 校验函数实现正确,过往问题已修复。
isGreaterThanGlobalRemainQuota和isGreaterThanMaxAmount正确地将bigint转换为字符串后再传给Decimal,避免了类型错误。status的依赖数组也已包含isValidMaxInputAmount,确保配置变更时状态能正确更新。
217-314: 输入处理逻辑结构清晰。通过将复杂的输入校验和格式化逻辑拆分为多个单一职责的辅助函数(
normalizeDotInput、sanitizeAllowedCharacters、normalizeAllZeroInteger等),handleInputChange的可读性和可维护性都得到了显著提升。这是处理复杂输入逻辑的良好实践。
316-474: 渲染逻辑清晰,状态处理得当。组件正确处理了焦点、错误状态下的文本颜色变化,余额展示逻辑区分了登录和未登录状态,全局限额提示也能根据配置正确显示。整体渲染结构合理。
packages/web3/src/swap-token/index.tsx (3)
185-224:handleValueInChange依赖数组完整。该回调的依赖数组已包含所有捕获的外部变量(
estFeeRate、estFee、token、calculateValueOut、onValueOutChange),过往审查中标记的依赖缺失问题已得到解决。
227-273: 输出值变化处理和币种切换逻辑正确。
handleValueOutChange的依赖数组完整,handleSwap函数正确处理了资金流向切换和输入输出值互换的逻辑。
315-405: 组件渲染结构合理,功能完整。主渲染逻辑正确组合了两个
CryptoInput组件,分别处理输入和输出。按钮的禁用逻辑全面(包括invalidInput、isCalculatingFee、buttonDisabled、showConnectButton),交换图标的交互行为也根据swap属性正确控制。类型导出清晰,组件整体实现完善。
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.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/web3/src/swap-token/CryptoInput.tsx (2)
135-147: 提取重复的输入验证逻辑
isGreaterThanGlobalRemainQuota和isGreaterThanMaxAmount两个函数包含大量相似的验证逻辑(检查长度、调用isValidValue、格式化金额等)。建议提取共同的验证逻辑到独立的辅助函数中,提高代码可维护性。参考实现:
// 通用的金额比较辅助函数 const isAmountGreaterThan = (value: string, compareTarget: bigint | undefined, enabled: boolean): boolean => { if (!enabled || !value?.length || !compareTarget) return false; if (!isValidValue(value)) return false; try { const result = formatAmount({ amount: value, decimals: token?.decimals }); return result.gt(Decimal(compareTarget.toString())); } catch (error) { return false; } }; const isGreaterThanGlobalRemainQuota = (value: string) => { if (!quota?.show || remainQuota === 0n) return !remainQuota; return isAmountGreaterThan(value, remainQuota, isValidMaxInputAmount); }; const isGreaterThanMaxAmount = (value: string) => { return isAmountGreaterThan(value, maxInputAmountValue, isValidMaxInputAmount); };Also applies to: 190-202
276-325: 拆分过长的 handleInputChange 函数
handleInputChange函数长达 50 行,包含多个职责:格式化处理、边界检查、小数位限制、前导零处理、最大值限制等。建议将其拆分为更小的、职责单一的辅助函数,以提高可读性和可维护性。当前的实现虽然功能正确,但过于冗长,难以理解和测试。已有的辅助函数(
normalizeDotInput、hasMultipleDecimalPoints等)是好的开始,但主函数仍然过于复杂。建议进一步重构,将验证和格式化逻辑分离:
const handleInputChange = (value: string) => { // 1. 基本格式化 const normalized = normalizeBasicInput(value); if (normalized === null) { setInputValue(inputValue ?? ''); return; } // 2. 小数和整数部分处理 const formatted = formatIntegerAndDecimal(normalized); // 3. 最大值检查 const final = enforceMaxAmount(formatted); setInputValue(final); };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/web3/src/swap-token/CryptoInput.tsx(1 hunks)packages/web3/src/swap-token/TokenSelector.tsx(1 hunks)packages/web3/src/swap-token/index.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: This is a multi-package React project built on Ant Design component library, designed to provide Web3 projects with wallet connection capabilities and DApp UI components
Applied to files:
packages/web3/src/swap-token/CryptoInput.tsxpackages/web3/src/swap-token/index.tsx
📚 Learning: 2025-11-25T09:58:18.233Z
Learnt from: CR
Repo: ant-design/ant-design-web3 PR: 0
File: .cursor/rules/basic.mdc:0-0
Timestamp: 2025-11-25T09:58:18.233Z
Learning: Applies to **/style/index.{ts,tsx} : Styling implementation should be based on `ant-design/cssinjs` and utilize Ant Design's Design Tokens for custom styling support
Applied to files:
packages/web3/src/swap-token/index.tsxpackages/web3/src/swap-token/TokenSelector.tsx
🧬 Code graph analysis (2)
packages/web3/src/swap-token/CryptoInput.tsx (6)
packages/web3/src/swap-token/TokenSelector.tsx (2)
T(41-92)TokenSelectorProps(9-24)packages/web3/src/swap-token/index.tsx (2)
Token(404-404)TokenConfig(404-404)packages/web3/src/swap-token/type.ts (2)
Token(3-21)TokenConfig(26-38)packages/web3/src/swap-token/constant.ts (1)
CUSTOMIZE_PREFIX_CLS(7-7)packages/web3/src/index.ts (1)
FundFlowDirection(18-18)packages/web3/src/swap-token/utils/format.ts (3)
formatAmount(71-83)formatValue(43-64)formatBalance(10-20)
packages/web3/src/swap-token/TokenSelector.tsx (3)
packages/web3/src/swap-token/type.ts (2)
TokenConfig(26-38)Token(3-21)packages/web3/src/index.ts (1)
FundFlowDirection(18-18)packages/web3/src/swap-token/constant.ts (1)
CUSTOMIZE_PREFIX_CLS(7-7)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: prepare preview
- GitHub Check: ci
🔇 Additional comments (7)
packages/web3/src/swap-token/CryptoInput.tsx (1)
1-488: 整体代码质量良好,核心功能实现完整CryptoInput 组件整体架构合理,功能完善:
- 输入验证逻辑严谨,支持整数、小数和千分位
- 全局限额和最大值校验机制完善
- 与 TokenSelector 集成良好
- 状态管理和事件处理得当
已正确修复了之前评审中指出的关键问题(bigint 转字符串、useEffect 依赖等)。
packages/web3/src/swap-token/TokenSelector.tsx (1)
1-92: 代码实现简洁清晰,符合最佳实践TokenSelector 组件设计合理:
- 泛型类型参数使用得当,支持类型安全的 token 操作
useMemo正确优化了 options 的计算,依赖数组完整- 根据
fundFlowDirection正确选择fromToken或toToken- 单个 token 时渲染静态标签,多个 token 时渲染下拉选择器,用户体验良好
renderTokenLabel作为独立导出函数,便于复用packages/web3/src/swap-token/index.tsx (5)
179-218: 输入值变化处理逻辑完善,依赖正确
handleValueInChange回调函数:
- 正确使用
useCallback优化性能- 依赖数组完整,包含所有使用的外部值
- 支持自定义计算函数
calculateValueOut和默认的手续费计算- 异常处理得当,防止程序崩溃
221-258: 输出值变化处理逻辑完善
handleValueOutChange回调函数实现合理:
- 使用
useCallback避免不必要的重渲染- 支持自定义
calculateValueIn和默认的网络费用计算- 边界条件处理完善(零值、空值等)
287-301: 手续费计算函数实现正确
handleCalculateFee使用useCallback包裹,依赖数组只包含onCalculateFee,符合预期。Loading 状态管理完善,正确处理了成功和异常两种情况。
310-314: useEffect 依赖完整,副作用处理正确Effect 在 token 或 valueIn 变化时重新计算手续费,依赖数组包含了所有使用的值(
token、valueIn、handleCalculateFee)。由于handleCalculateFee已经用useCallback包裹,不会导致无限循环。
1-406: SwapToken 组件架构优秀,功能完整主组件设计亮点:
- 完善的类型定义(SwapInputProps、SwapInputRef、SwapTokenComponent)
- 使用 forwardRef 暴露 reset 方法,便于父组件控制
- 双向输入联动逻辑清晰(handleValueInChange ↔ handleValueOutChange)
- 支持自定义计算函数和默认计算逻辑
- 手续费自动计算机制合理
- 按钮状态管理完善(invalidInput、loading、disabled 等)
- 良好的扩展性(extra、extraRenders、underButtonRender 等插槽)
之前评审中的关键问题均已修复:
- useCallback 依赖完整
- 异常处理使用 finally 块
- 移除了注释代码
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.
Actionable comments posted: 2
🧹 Nitpick comments (2)
packages/web3/src/swap-token/CryptoInput.tsx (2)
91-96:maxInputAmountValue的三元表达式嵌套较深,建议考虑简化。当前逻辑正确,但嵌套三元表达式可读性较差。可考虑提取为独立函数或使用 if-else 结构。
- const maxInputAmountValue = - maxInputAmount?.symbol === token?.symbol - ? (balance?.amount ?? 0n) > BigInt(maxInputAmount?.amount || 0n) - ? maxInputAmount?.amount || 0n - : balance?.amount - : balance?.amount; + const maxInputAmountValue = React.useMemo(() => { + if (maxInputAmount?.symbol !== token?.symbol) { + return balance?.amount; + } + const balanceAmt = balance?.amount ?? 0n; + const maxAmt = maxInputAmount?.amount ?? 0n; + return balanceAmt > maxAmt ? maxAmt : balanceAmt; + }, [maxInputAmount, token?.symbol, balance?.amount]);
320-328: 建议使用设计令牌替代硬编码颜色值。
#FF4D4F、#326CFF等硬编码颜色值可考虑使用 Ant Design 的主题令牌(如token.colorError、token.colorPrimary),以保持与设计系统的一致性。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/web3/src/swap-token/CryptoInput.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/web3/src/swap-token/CryptoInput.tsx (5)
packages/web3/src/swap-token/TokenSelector.tsx (2)
T(41-92)TokenSelectorProps(9-24)packages/web3/src/swap-token/type.ts (2)
Token(3-21)TokenConfig(26-38)packages/web3/src/swap-token/constant.ts (2)
CUSTOMIZE_PREFIX_CLS(7-7)AMOUNT_IN_DECIMALS(4-4)packages/web3/src/index.ts (1)
FundFlowDirection(18-18)packages/web3/src/swap-token/utils/format.ts (2)
formatAmount(71-83)formatValue(43-64)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: ci
- GitHub Check: prepare preview
🔇 Additional comments (4)
packages/web3/src/swap-token/CryptoInput.tsx (4)
1-52: 接口定义和导入结构清晰。接口文档完善,泛型约束合理,类型定义正确。
98-132: 金额校验逻辑完整。
isValidValue函数正确处理了整数、小数和千分位分隔符的各种边界情况。
268-317: 输入处理逻辑重构良好。
handleInputChange通过调用多个职责单一的辅助函数(normalizeDotInput、sanitizeAllowedCharacters、normalizeLeadingZero等)实现了清晰的验证流程,可读性和可维护性较好。
377-478: 组件渲染结构清晰。JSX 布局合理,正确使用了
classNames进行样式管理,全局限额提示区域的条件渲染逻辑正确。

[中文版模板 / Chinese template]
💡 Background and solution
Swap Token Component

🔗 Related issue link
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.