-
Notifications
You must be signed in to change notification settings - Fork 16
feat: prop tokenId #595
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: master
Are you sure you want to change the base?
feat: prop tokenId #595
Conversation
📝 WalkthroughWalkthroughAdds optional tokenId end-to-end: DOM allowance, new prop on PayButton → PaymentDialog → Widget, token-aware Chronik utilities and websocket plumbing, token-specific URL/QR/donation behavior, and documentation updates for tokenId. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant PayButton
participant PaymentDialog
participant Widget
participant ChronikUtil
participant ChronikWS
User->>PayButton: instantiate (props incl. tokenId?)
PayButton->>PaymentDialog: open (pass tokenId)
PaymentDialog->>Widget: render (pass tokenId)
alt tokenId provided
Widget->>ChronikUtil: getTokenInfo(tokenId, address)
ChronikUtil-->>Widget: token metadata
Widget->>Widget: set tokenName / icon
Widget->>ChronikWS: setupChronikWebSocket(address, setNewTx, tokenId)
else no tokenId
Widget->>ChronikWS: setupChronikWebSocket(address, setNewTx)
end
ChronikWS->>ChronikWS: receive websocket msg
ChronikWS->>ChronikUtil: parseWebsocketMessage(msg, setNewTx, chronik, address, tokenId?)
alt tokenId present in parse
ChronikUtil->>ChronikUtil: getTokenAmount(tx, tokenId, address)
ChronikUtil-->>ChronikWS: token-aware transaction
else
ChronikUtil-->>ChronikWS: normal transaction
end
ChronikWS-->>Widget: newTx event (token-aware if applicable)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (12)
🚧 Files skipped from review as they are similar to previous changes (6)
🧰 Additional context used🧬 Code graph analysis (2)react/lib/util/chronik.ts (2)
react/lib/components/Widget/Widget.tsx (2)
🪛 Biome (2.1.2)react/lib/util/chronik.ts[error] 265-265: This hook is being called indirectly and conditionally, but all hooks must be called in the exact same order in every component render. This is the call path until the hook. For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order. (lint/correctness/useHookAtTopLevel) 🪛 Gitleaks (8.30.0)docs/README.md[high] 1143-1143: Detected a Generic API Key, potentially exposing access to various services and sensitive operations. (generic-api-key) [high] 1149-1149: Detected a Generic API Key, potentially exposing access to various services and sensitive operations. (generic-api-key) [high] 1155-1155: Detected a Generic API Key, potentially exposing access to various services and sensitive operations. (generic-api-key) 🪛 markdownlint-cli2 (0.18.1)docs/zh-tw/README.md1135-1135: Heading levels should only increment by one level at a time (MD001, heading-increment) ⏰ 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). (1)
🔇 Additional comments (12)
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.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
react/lib/util/chronik.ts (1)
166-184: Add error handling for token amount calculation.The call to
getTokenAmount(line 171) lacks error handling. If token amount calculation fails, it will throw an unhandled error.🔎 Recommended fix
const getTransactionFromChronikTransaction = async (transaction: Tx, address: string, tokenId?: string): Promise<Transaction> => { const { amount, opReturn } = await getTransactionAmountAndData(transaction, address) const parsedOpReturn = resolveOpReturn(opReturn) const networkSlug = getAddressPrefix(address) const inputAddresses = getSortedInputAddresses(networkSlug, transaction) - const tokenAmount = tokenId ? await getTokenAmount(transaction, tokenId, address, networkSlug) : undefined; + let tokenAmount: string | undefined; + if (tokenId) { + try { + // Fetch token decimals from token info + const tokenInfo = await getTokenInfo(tokenId, address); + const decimals = tokenInfo.genesisInfo.decimals; + tokenAmount = await getTokenAmount(transaction, tokenId, address, networkSlug, decimals); + } catch (err) { + console.error('Failed to calculate token amount:', err); + tokenAmount = '0'; + } + } return { hash: transaction.txid, amount: tokenId ? tokenAmount! : amount, address, timestamp: transaction.block !== undefined ? transaction.block.timestamp : transaction.timeFirstSeen, confirmed: transaction.block !== undefined, opReturn, paymentId: parsedOpReturn?.paymentId ?? '', message: parsedOpReturn?.message ?? '', rawMessage: parsedOpReturn?.rawMessage ?? '', inputAddresses, } }
🧹 Nitpick comments (3)
react/lib/components/Widget/Widget.tsx (2)
501-503: Consider adding validation for the tokenId parameter.The helper constructs an icon URL without validating the tokenId. While image loading failures are typically handled by the browser, consider adding basic validation (non-empty, expected format) to avoid constructing invalid URLs.
🔎 Optional: Add basic validation
const getTokenIconUrl = useCallback((tokenId: string): string => { + if (!tokenId || typeof tokenId !== 'string' || tokenId.trim() === '') { + throw new Error('Invalid tokenId provided'); + } return `https://icons.etokens.cash/128/${tokenId}.png` }, [])
845-845: Handle null tokenName in display text.If
tokenNameis null (e.g., token info fetch failed or tokenTicker is undefined), the display text will show "null" to users. Consider providing a fallback.🔎 Proposed fix
-setText(`Send ${amountToDisplay} ${tokenId ? tokenName : cur}`) +setText(`Send ${amountToDisplay} ${tokenId ? (tokenName || 'token') : cur}`)-setText(`Send any amount of ${tokenId ? tokenName : thisAddressType}`) +setText(`Send any amount of ${tokenId ? (tokenName || 'token') : thisAddressType}`)Also applies to: 849-850
react/lib/util/chronik.ts (1)
258-269: Consider documenting error handling expectations.The
getTokenInfofunction lacks error handling and will propagate errors to callers. While this is acceptable, ensure all call sites properly handle potential failures (network errors, invalid tokenId, etc.).
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
paybutton/src/index.tsxreact/lib/components/PayButton/PayButton.tsxreact/lib/components/PaymentDialog/PaymentDialog.tsxreact/lib/components/Widget/Widget.tsxreact/lib/util/chronik.tsreact/lib/util/socket.ts
🧰 Additional context used
🧬 Code graph analysis (2)
react/lib/util/socket.ts (2)
react/lib/util/chronik.ts (1)
initializeChronikWebsocket(296-323)react/lib/util/types.ts (1)
Transaction(10-21)
react/lib/components/Widget/Widget.tsx (3)
react/lib/util/chronik.ts (1)
getTokenInfo(258-269)react/lib/util/format.ts (1)
amount(5-12)react/lib/util/address.ts (1)
isValidCashAddress(4-13)
🔇 Additional comments (10)
react/lib/util/socket.ts (1)
125-125: LGTM! Clean parameter propagation.The tokenId parameter is properly threaded through the interface and passed to initializeChronikWebsocket, consistent with the token-aware flow.
Also applies to: 149-155
paybutton/src/index.tsx (1)
109-109: LGTM! Properly enables tokenId as a recognized prop.The addition to allowedProps enables DOM attribute parsing and forwarding of tokenId to PayButton/Widget components.
react/lib/components/PaymentDialog/PaymentDialog.tsx (1)
70-70: LGTM! Clean prop forwarding.The tokenId is properly threaded from PaymentDialogProps through to WidgetContainer, enabling token support in the dialog flow.
Also applies to: 134-134, 264-264
react/lib/components/PayButton/PayButton.tsx (1)
62-62: LGTM! Proper tokenId integration.The tokenId is correctly added to PayButtonProps and forwarded to both the Chronik WebSocket setup (for transaction monitoring) and PaymentDialog (for UI rendering).
Also applies to: 97-97, 298-298, 456-456
react/lib/components/Widget/Widget.tsx (5)
1070-1070: LGTM! Proper QR code icon selection for tokens.The image selection correctly prioritizes token icons when tokenId is present, falling back to the appropriate BCH or XEC logo based on the address format.
854-854: LGTM! Effect dependencies are complete.The effect dependencies properly include both
tokenNameandtokenId, which are used within the effect for URL generation and display text.
546-546: LGTM! TokenId properly propagated to WebSocket setup.The tokenId is correctly passed to the Chronik WebSocket setup for transaction monitoring in standalone widget mode.
55-55: LGTM! Proper setup for token support.The imports, prop additions, and state initialization properly establish the foundation for token functionality in the Widget component.
Also applies to: 118-118, 179-179, 330-330
976-1021: Verify token payment URL parameter names with Cashtab protocol.The code confirms that donation functionality is intentionally disabled for token payments (lines 993-1004 do not append donation address/amount parameters when
tokenIdis present), while donations work normally for XEC/BCH payments.Please verify that
token_decimalized_qtyandtoken_idare the correct parameter names for the Cashtab wallet's token payment protocol.react/lib/util/chronik.ts (1)
271-277: LGTM! Proper tokenId propagation through WebSocket flow.The tokenId parameter is consistently threaded through the WebSocket initialization and message parsing functions, enabling token-aware transaction detection.
Also applies to: 287-287, 296-299, 314-315
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: 3
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
docs/README.mddocs/_sidebar.mddocs/zh-cn/README.mddocs/zh-cn/_sidebar.mddocs/zh-tw/README.mddocs/zh-tw/_sidebar.md
🧰 Additional context used
🪛 Gitleaks (8.30.0)
docs/zh-tw/README.md
[high] 1138-1138: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1144-1144: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1150-1150: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
docs/README.md
[high] 1143-1143: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1149-1149: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1155-1155: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 markdownlint-cli2 (0.18.1)
docs/zh-tw/README.md
1135-1135: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4
(MD001, heading-increment)
1135-1135: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1135-1135: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1141-1141: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1141-1141: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1147-1147: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1147-1147: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
docs/README.md
1139-1139: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4
(MD001, heading-increment)
1139-1139: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1139-1139: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1145-1145: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1145-1145: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1151-1151: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1151-1151: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
🔇 Additional comments (3)
docs/_sidebar.md (1)
37-38: Navigation link correctly added.The token-id sidebar entry is properly formatted and the anchor
?id=token-idcorresponds to the## token-idheading in the documentation.docs/zh-tw/_sidebar.md (1)
35-37: Navigation sidebar properly localized.The addition of both donation-rate and token-id entries improves consistency across localized sidebar versions.
docs/zh-cn/_sidebar.md (1)
36-37: Navigation entry properly added.The token-id sidebar link is correctly positioned and formatted, maintaining consistency with other parameter navigation entries.
| ## token-id | ||
|
|
||
| > **「tokenId」 参数用于定义在按钮或小组件中使用的 eToken。** | ||
| ?> tokenId 参数是可选的。它接受一个包含 token ID 的字符串。默认值为 null。 | ||
|
|
||
|
|
||
| **Example:** | ||
| <!-- tabs:start --> | ||
|
|
||
| #### ** HTML ** | ||
|
|
||
| ```html | ||
| token-id="c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4" | ||
| ``` | ||
|
|
||
| #### ** JavaScript ** | ||
|
|
||
| ```javascript | ||
| tokenId: "c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4" | ||
| ``` | ||
|
|
||
| #### ** React ** | ||
|
|
||
| ```react | ||
| tokenId = "c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4" | ||
| ``` | ||
| <!-- tabs:end --> | ||
|
|
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.
🧩 Analysis chain
🏁 Script executed:
# First, let's check the actual file and look at the specific lines
cat -n docs/zh-cn/README.md | sed -n '1129,1157p'Repository: PayButton/paybutton
Length of output: 761
🏁 Script executed:
# Also check if markdownlint is available and what it reports for this section
which markdownlint && markdownlint docs/zh-cn/README.md | grep -E "1129|1130|1131|1132|1133|1134|1135|1136|1137|1138|1139|1140|1141|1142|1143|1144|1145|1146|1147|1148|1149|1150|1151|1152|1153|1154|1155|1156|1157" || echo "markdownlint not available"Repository: PayButton/paybutton
Length of output: 150
🏁 Script executed:
# Alternative: Check if there are linting tools in the repo
find . -name ".markdownlintrc*" -o -name "markdownlint*" -o -name ".lintrc*" | head -20Repository: PayButton/paybutton
Length of output: 45
Fix markdown linting violations: spaces in tab heading emphasis markers and heading level increment.
The section contains formatting issues in the tab headings:
- Lines 1139, 1145, 1151: Spaces inside emphasis markers (
#### ** HTML **should be#### **HTML**, etc.) - Heading structure jumps from h2 to h4, skipping h3 level
🤖 Prompt for AI Agents
In docs/zh-cn/README.md around lines 1129 to 1157, the tab heading emphasis
markers contain extraneous spaces and the heading level jumps from h2 to h4;
remove the spaces inside the emphasis markers so headings read like "####
**HTML**", "#### **JavaScript**", "#### **React**" (no spaces between ** and
text) and adjust the heading levels to follow the document structure (use h3 if
the section should be one level below the current h2, or otherwise ensure
headings increment sequentially) so linting and document hierarchy are correct.
| ## token-id | ||
|
|
||
| > **「tokenId」 參數用於定義在按鈕或小工具中使用的 eToken。** | ||
| ?> tokenId 參數為選填。它接受一個包含 token ID 的字串。預設值為 null。 | ||
|
|
||
|
|
||
| **Example:** | ||
| <!-- tabs:start --> | ||
|
|
||
| #### ** HTML ** | ||
|
|
||
| ```html | ||
| token-id="c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4" | ||
| ``` | ||
|
|
||
| #### ** JavaScript ** | ||
|
|
||
| ```javascript | ||
| tokenId: "c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4" | ||
| ``` | ||
|
|
||
| #### ** React ** | ||
|
|
||
| ```react | ||
| tokenId = "c67bf5c2b6d91cfb46a5c1772582eff80d88686887be10aa63b0945479cf4ed4" | ||
| ``` | ||
| <!-- tabs:end --> | ||
|
|
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, check if markdownlint is available, if not install it
if ! command -v markdownlint &> /dev/null; then
npm install -g markdownlint-cli 2>/dev/null || pip install markdownlint-md 2>/dev/null || echo "Installing markdownlint..."
fi
# Check markdown files exist
echo "=== Checking files ==="
ls -la docs/zh-tw/README.md docs/zh-cn/README.md 2>&1 | head -20
# Get line counts for context
echo -e "\n=== File line counts ==="
wc -l docs/zh-tw/README.md docs/zh-cn/README.md
# Extract the token-id section from zh-tw file (lines 1125-1153)
echo -e "\n=== zh-tw token-id section (lines 1125-1153) ==="
sed -n '1125,1153p' docs/zh-tw/README.md | cat -n
# Extract the same section from zh-cn for comparison
echo -e "\n=== zh-cn token-id section (approx same location) ==="
sed -n '1125,1153p' docs/zh-cn/README.md | cat -nRepository: PayButton/paybutton
Length of output: 149
🏁 Script executed:
#!/bin/bash
# Try to run markdownlint on the specific files if available
if command -v markdownlint &> /dev/null; then
echo "=== Markdown linting results for zh-tw ==="
markdownlint docs/zh-tw/README.md 2>&1 | grep -A 10 "token-id" || markdownlint docs/zh-tw/README.md 2>&1 | grep -A 10 "1131\|1137\|1143" || markdownlint docs/zh-tw/README.md 2>&1 | head -50
fi
# Check for markdownlint configuration files
echo -e "\n=== Looking for markdownlint config ==="
find . -maxdepth 3 -name ".markdownlint*" -o -name "markdownlint*" | head -10Repository: PayButton/paybutton
Length of output: 103
🏁 Script executed:
#!/bin/bash
# Read specific lines from zh-tw README
echo "=== Lines 1125-1153 from docs/zh-tw/README.md ==="
sed -n '1125,1153p' docs/zh-tw/README.md
echo -e "\n=== Checking line 1131 specifically ==="
sed -n '1131p' docs/zh-tw/README.md | cat -A
echo -e "\n=== Lines around emphasis markers (1131, 1137, 1143) ==="
sed -n '1130,1145p' docs/zh-tw/README.md | cat -nRepository: PayButton/paybutton
Length of output: 1078
🏁 Script executed:
#!/bin/bash
# Compare with zh-cn version
echo "=== Lines 1125-1153 from docs/zh-cn/README.md ==="
sed -n '1125,1153p' docs/zh-cn/README.md
echo -e "\n=== Check line 1131 in zh-cn ==="
sed -n '1131p' docs/zh-cn/README.md | cat -A
echo -e "\n=== Lines around emphasis markers in zh-cn (1131, 1137, 1143) ==="
sed -n '1130,1145p' docs/zh-cn/README.md | cat -nRepository: PayButton/paybutton
Length of output: 1248
Fix markdown linting violations in the token-id section.
The file contains markdown linting violations:
- MD001: Heading level jump from
##to####without intermediate### - MD037: Spaces inside emphasis markers in
** HTML **,** JavaScript **, and** React **
These match the same violations present in the Simplified Chinese version.
🧰 Tools
🪛 Gitleaks (8.30.0)
[high] 1138-1138: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1144-1144: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1150-1150: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 markdownlint-cli2 (0.18.1)
1135-1135: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4
(MD001, heading-increment)
1135-1135: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1135-1135: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1141-1141: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1141-1141: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1147-1147: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
1147-1147: Spaces inside emphasis markers
(MD037, no-space-in-emphasis)
🤖 Prompt for AI Agents
In docs/zh-tw/README.md around lines 1125 to 1153, the token-id section has
markdown lint issues: the subheadings jump from ## to #### and the bold labels
contain spaces inside the emphasis markers. Fix by adjusting the subheading
levels to follow ## -> ### (or add a ### level before the current ####) so
headings increment by one level, and remove spaces inside the bold markers
(change "** HTML **", "** JavaScript **", "** React **" to "**HTML**",
"**JavaScript**", "**React**") to satisfy MD001 and MD037.
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
react/lib/components/Widget/Widget.tsx (1)
1026-1028: MissingtokenIdinresolveUrldependency array.The
resolveUrlcallback usestokenId(lines 1000, 1007, 1020) but it's not included in the dependency array at line 1027. This could cause stale closure issues iftokenIdchanges after initial render.🔎 Proposed fix
- [disabled, to, opReturn, userDonationRate, donationAddress, donationEnabled, shouldApplyDonation] + [disabled, to, opReturn, userDonationRate, donationAddress, donationEnabled, shouldApplyDonation, tokenId]
♻️ Duplicate comments (1)
react/lib/util/chronik.ts (1)
116-135: Precision loss from integer division inside the loop.The division by
BigInt(divisor)at line 129 happens per-output before summing. BigInt division truncates, so this causes precision loss when multiple outputs exist.For example with 2 decimals: two outputs of 150 atoms each would calculate as
(150/100) + (150/100) = 1 + 1 = 2instead of(150+150)/100 = 3.🔎 Proposed fix: sum atoms first, then divide
const getTokenAmount = async (transaction: Tx, tokenId: string, address: string, networkSlug: string): Promise<string> => { let totalTokenOutput = BigInt(0); const tokenInfo = await getTokenInfo(tokenId, address); const decimals = tokenInfo.genesisInfo.decimals; const divisor = 10 ** decimals; for (const output of transaction.outputs) { if (output.token?.tokenId === tokenId) { const outputAddress = outputScriptToAddress(networkSlug, output.outputScript) if(outputAddress === address) { const atoms = BigInt(output.token.atoms); - totalTokenOutput += atoms / BigInt(divisor); + totalTokenOutput += atoms; } } } - return totalTokenOutput.toString(); + // Convert from atoms to decimalized string + const divisorBigInt = BigInt(divisor); + const integerPart = totalTokenOutput / divisorBigInt; + const remainder = totalTokenOutput % divisorBigInt; + + if (remainder === BigInt(0) || decimals === 0) { + return integerPart.toString(); + } + + const remainderStr = remainder.toString().padStart(decimals, '0'); + return `${integerPart}.${remainderStr}`.replace(/\.?0+$/, ''); }
🧹 Nitpick comments (2)
react/lib/util/chronik.ts (2)
169-187: Non-null assertion on tokenAmount is acceptable but consider defensive handling.Line 177's
tokenAmount!assertion relies on the prior conditional at line 174. While this works, ifgetTokenAmountwere to returnundefinedunexpectedly (e.g., API failure), this would throw at runtime.🔎 Optional: defensive fallback
- amount: tokenId ? tokenAmount! : amount, + amount: tokenId && tokenAmount ? tokenAmount : amount,
261-272: Consider caching token info or reusing ChronikClient.
getTokenInfocreates a newChronikClienton every call. WhengetTokenAmountcalls this internally for each transaction, it results in redundant client instantiation and API calls for the same token.Consider memoizing token info or passing the client/token info as a parameter to avoid repeated lookups for the same tokenId.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
docs/README.mddocs/zh-cn/README.mddocs/zh-tw/README.mdreact/lib/components/Widget/Widget.tsxreact/lib/util/chronik.ts
🧰 Additional context used
🧬 Code graph analysis (2)
react/lib/util/chronik.ts (3)
react/lib/util/types.ts (1)
Transaction(10-21)react/lib/util/address.ts (1)
getAddressPrefix(52-64)react/lib/util/format.ts (1)
amount(5-12)
react/lib/components/Widget/Widget.tsx (1)
react/lib/util/chronik.ts (1)
getTokenInfo(261-272)
🪛 Biome (2.1.2)
react/lib/util/chronik.ts
[error] 265-265: This hook is being called indirectly and conditionally, but all hooks must be called in the exact same order in every component render.
This is the call path until the hook.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
🪛 Gitleaks (8.30.0)
docs/README.md
[high] 1143-1143: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1149-1149: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1155-1155: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
docs/zh-cn/README.md
[high] 1142-1142: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1148-1148: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1154-1154: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
docs/zh-tw/README.md
[high] 1138-1138: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1144-1144: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 1150-1150: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 markdownlint-cli2 (0.18.1)
docs/zh-cn/README.md
1135-1135: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4
(MD001, heading-increment)
🔇 Additional comments (6)
docs/zh-cn/README.md (1)
1129-1157: Token-id documentation looks good.The new
token-idparameter documentation is clear and consistent with the existing parameter sections. The Gitleaks warnings about "Generic API Key" on the example token ID strings are false positives—these are clearly documentation examples showing the expected format, not actual secrets.The heading level increment (h2 to h4) flagged by markdownlint follows the same docsify tabs pattern used throughout this document for other parameters.
docs/zh-tw/README.md (1)
1125-1155: Token-id documentation is consistent with other locales.The Traditional Chinese documentation for the
token-idparameter is well-structured and consistent with the Simplified Chinese and English versions. The Gitleaks warnings are false positives for documentation example strings.docs/README.md (1)
1130-1158: Token-id documentation is complete and accurate.The English documentation for the
token-idparameter correctly describes its purpose, optionality, and default value. Examples are provided for all three integration methods (HTML, JavaScript, React). The Gitleaks warnings are false positives for documentation example strings.react/lib/components/Widget/Widget.tsx (3)
595-613: Token info fetching now has proper error handling.The effect correctly implements try/catch/finally with appropriate error state management. The redundant
tokenId !== nullcheck mentioned in the past review has also been removed.
1000-1011: Donation is not applied to token payment URLs.When
tokenIdis present andshouldApplyDonationreturns true, the donation address and amount are not included in the URL (lines 1001-1002). Onlytoken_decimalized_qtyis added.This might be intentional if token payment URLs don't support multi-output donations, but it means the donation UI will show the donation rate even though it won't be applied.
Please verify this is the intended behavior. If donations should be hidden for token payments, consider disabling the donation UI when
tokenIdis present.
1069-1085: Token icon integration in QR code looks good.The icon selection logic correctly handles all cases: success state shows checkmark, token payments show token icon, otherwise appropriate chain icon based on address type.
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
🧹 Nitpick comments (1)
react/lib/components/Widget/Widget.tsx (1)
595-613: Remove redundant check and handle null tokenName display.Two minor improvements:
- The check
tokenId !== ''on line 597 is redundant since an empty string is falsy- When
tokenNameisnull(during loading, on error, or iftokenTickeris missing), the UI text on lines 852 and 856 will display the string "null"🔎 Suggested improvements
useEffect(() => { ;(async (): Promise<void> => { - if (tokenId && tokenId !== '') { + if (tokenId) { try { const tokenInfo = await getTokenInfo(tokenId, to) - const name = tokenInfo.genesisInfo.tokenTicker ?? null + const name = tokenInfo.genesisInfo.tokenTicker ?? 'Token' setTokenName(name) } catch (err) { console.error('Failed to fetch token info:', err) - setTokenName(null) + setTokenName('Token') setErrorMsg('Unable to load token information') } finally { setLoading(false) } return } setLoading(false) })() }, [tokenId, to])Alternatively, update the text rendering to provide a fallback:
- setText(`Send ${amountToDisplay} ${tokenId ? tokenName : cur}`) + setText(`Send ${amountToDisplay} ${tokenId ? (tokenName || 'Token') : cur}`)
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
react/lib/components/Widget/Widget.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
react/lib/components/Widget/Widget.tsx (2)
react/lib/util/chronik.ts (1)
getTokenInfo(261-272)react/lib/util/address.ts (1)
isValidCashAddress(4-13)
🔇 Additional comments (5)
react/lib/components/Widget/Widget.tsx (5)
55-55: LGTM!The tokenId prop is correctly added to the interface and properly imported/destructured.
Also applies to: 118-118, 179-179
330-330: LGTM!The tokenName state and getTokenIconUrl helper are implemented correctly.
Also applies to: 501-503
546-546: LGTM!The tokenId is correctly passed to the websocket setup, and the effect dependencies are properly updated to include both tokenName and tokenId.
Also applies to: 861-861
983-1028: Verify donation support for token payments.The URL generation logic differs between regular and token payments when donations are enabled. For token payments (lines 1000-1005), only
token_decimalized_qtyis added without the donation address and amount parameters that are included for regular payments (line 1004).Is this intentional? If token payments don't support donations to the PayButton team, this behavior is correct. Otherwise, the donation parameters should be included for token payments as well.
1077-1077: LGTM!The QR code correctly displays the token icon when tokenId is present, with appropriate fallbacks for success state and regular BCH/XEC addresses.
356e9e8 to
7dc3553
Compare
Related to #44
Description
Description
This PR adds full support for token-based payments and updates the payment flow accordingly.
Changes included:
Accepts a
token-idparameter to enable token-specific paymentsDetects and validates payments for the specified token
Fetches the token icon and displays it in the QR code
Updates the dialog text to display the token ticker (e.g., Send 10 XECX)
Updates the payment URL to include
token_idandtoken_decimalized_qty, removing unused parametersWill continue the following remaining steps in another PR:
Test plan
Create a button with
token-idparam check dialog text, qrcode icon. Copy the payment url check if it contains thetoken-id, test the payment url in cashtab, make a payment with the specifications of the button and make sure the payment is detected.Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.