feat: add example website and improve SDK widget UI/UX & validation flow#105
feat: add example website and improve SDK widget UI/UX & validation flow#105DeveloperAmrit wants to merge 6 commits into
Conversation
|
Warning Review limit reached
More reviews will be available in 38 minutes and 52 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR implements a unified payment flow and robust error handling for the StablePay widget, addressing friction in the two-step Prepare/Send transaction process. It adds a complete example application demonstrating SDK integration, improves transaction error classification using JSON-RPC codes, refactors the payment state machine into a single Pay action, and redesigns the payment dialog styling. ChangesStablePay Payment UX and Example Application
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as TransactionReview
participant WalletClient
participant RPC as Network/RPC
User->>UI: Click Pay
UI->>UI: interactionState = CONFIRMING
User->>UI: Confirm
UI->>UI: interactionState = PENDING
UI->>UI: ensureCorrectNetwork()
UI->>WalletClient: sendTransaction()
WalletClient->>RPC: eth_sendTransaction
RPC-->>WalletClient: txHash
WalletClient-->>UI: txHash
UI->>UI: Set txHash, interactionState = IDLE
UI->>User: Show transaction link + success
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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.
Actionable comments posted: 7
🧹 Nitpick comments (3)
stablepay-sdk/src/widget/Dialog.jsx (1)
13-13: ⚡ Quick winKeep semantic heading for dialog title.
Line 13 swaps
<h2>to<div>, which drops document/assistive heading semantics. Prefer keeping a heading tag here.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@stablepay-sdk/src/widget/Dialog.jsx` at line 13, In the Dialog component replace the non-semantic <div className={styles.stablepayTitle}>StablePay</div> with a proper heading element (e.g. <h2 className={styles.stablepayTitle}>StablePay</h2>) so the title retains document/assistive heading semantics; keep the same className (styles.stablepayTitle) and styling, and ensure the Dialog component still meets any aria-labelledby usage if present.stablepay-sdk/example/index.html (1)
7-7: 💤 Low valueUpdate page title to be more descriptive.
The generic title "example" should be updated to reflect the purpose of this demonstration application.
💡 Suggested improvement
- <title>example</title> + <title>StablePay SDK Example</title>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@stablepay-sdk/example/index.html` at line 7, Replace the generic HTML title tag content (<title>example</title>) with a more descriptive string that reflects the page purpose (e.g., "StablePay SDK Demo" or "StablePay SDK Example - Payment Integration Demo"); update the <title> element in the document head so it clearly identifies this demonstration app for users and search engines.stablepay-sdk/example/README.md (1)
1-17: ⚡ Quick winEnhance README with example-specific documentation.
This README contains only generic Vite+React template boilerplate and doesn't explain:
- The purpose of this example (demonstrating StablePay SDK integration)
- How to install dependencies and run the example (
npm install,npm run dev)- What the example demonstrates (wallet connection, network/token selection, transaction flow)
- How to use the SDK in your own project
📝 Suggested documentation structure
# StablePay SDK Example This example demonstrates how to integrate the StablePay SDK into a React application using Vite. ## Features Demonstrated - Wallet connection and management - Network and token selection - Transaction preparation and execution - Success/error handling ## Getting Started ```bash # Install dependencies npm install # Run development server npm run devUsage
The example shows how to:
- Import and configure the StablePay widget
- Handle transaction completion callbacks
- Manage wallet states
See
src/App.jsxfor the integration code.Additional Notes
This template uses
@vitejs/plugin-reactwith HMR and ESLint rules.</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@stablepay-sdk/example/README.mdaround lines 1 - 17, The README currently
contains only generic Vite+React boilerplate; update it to describe this example
as the "StablePay SDK Example", briefly state its purpose (demonstrating
StablePay SDK integration), list features demonstrated (wallet
connection/management, network & token selection, transaction
preparation/execution, success/error handling), add Getting Started steps (npm
install, npm run dev) and Usage notes that point to the integration code in
src/App.jsx (importing/configuring the StablePay widget, handling transaction
callbacks, managing wallet state); keep the existing note about the React
compiler and plugin links but replace template-specific text with these
example-specific instructions and a short Features/Usage section.</details> <!-- cr-comment:v1:bd7ab29875e4640f237f5211 --> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.Inline comments:
In@stablepay-sdk/example/eslint.config.js:
- Around line 11-15: The ESLint flat config currently uses an unsupported
"extends" array; replace that usage by directly spreading the config objects
into the exported array — locate the extends block referencing
js.configs.recommended, reactHooks.configs.flat.recommended, and
reactRefresh.configs.vite and change it to spread those config objects at the
top level of the flat config export so the configs are merged correctly.In
@stablepay-sdk/example/package.json:
- Around line 12-18: Remove the unused ethers dependency from the example app by
deleting the "ethers" entry in stablepay-sdk/example/package.json and then
regenerate the lockfile (package-lock.json) by running the package manager
(e.g., npm install) inside stablepay-sdk/example; ensure no code in
stablepay-sdk/example/src imports "ethers" (the widget uses viem, see
stablepay-sdk/src/widget/TransactionReview.jsx) before committing the updated
package.json and package-lock.json.In
@stablepay-sdk/example/src/App.jsx:
- Around line 8-19: The header's local wallet flow is uncoordinated with the SDK
widget: remove the header "Connect Wallet" button and the related local state
and function (remove the header button JSX, the account state variable and the
connectWallet function) so the app relies solely on
StablePay.Widget/WalletProvider for wallet connections; ensure any imports or
variables only used by connectWallet are also cleaned up and add a short comment
near StablePay.Widget/WalletProvider noting it now owns wallet handling.- Around line 33-35: The alert callback handleTransactionComplete currently
takes a string hash but TransactionReview calls onTransactionComplete with an
object payload; change handleTransactionComplete to accept and destructure the
payload (e.g., ({ txHash, network, token }) or payload) and use txHash in the
alert (with a fallback if missing) so the actual transaction hash is shown;
update any references to handleTransactionComplete to match the new signature
and keep onTransactionComplete usage in TransactionReview unchanged.In
@stablepay-sdk/src/core/Transaction.js:
- Around line 56-57: The isConnectionError check in Transaction.js incorrectly
treats error.code === 4001 as an RPC connection failure; remove 4001 from the
isConnectionError condition in the isConnectionError declaration inside the
Transaction handling logic and instead handle error.code === 4001 as a
user-rejection case (consistent with WalletContext.jsx and
TransactionReview.jsx), e.g., branch separately to return/throw a user-rejection
error or status so 4001 is no longer classified as a connection error.- Around line 33-34: The revert detection in Transaction.init is too loose:
replace the current check that treats any truthy contractError.data as a revert
by narrowing to explicit revert signatures or types (e.g., check if
contractError is an instance of ContractFunctionRevertedError or if
contractError.data exists and contractError.data.message (or contractError.data
&& contractError.data.message) contains a revert indicator like "execution
reverted" or other contract revert text); update the isReverted computation in
Transaction.init to use these stricter conditions (reference the contractError
variable and Transaction.init function) so provider/RPC errors with generic data
are not misclassified as contract reverts.In
@stablepay-sdk/src/widget/TransactionReview.jsx:
- Around line 101-104: The button's onClick uses window.open(url, '_blank')
which is vulnerable to tabnabbing; update the click handler in
TransactionReview.jsx to call window.open('https://metamask.io/download/',
'_blank', 'noopener,noreferrer') (or alternatively set the returned window's
opener to null) so the opened page cannot access window.opener.
Nitpick comments:
In@stablepay-sdk/example/index.html:<title> element in the document head so it clearly identifies this demonstration app for users and search engines.
- Line 7: Replace the generic HTML title tag content (<title>example</title>)
with a more descriptive string that reflects the page purpose (e.g., "StablePay
SDK Demo" or "StablePay SDK Example - Payment Integration Demo"); update theIn
@stablepay-sdk/example/README.md:
- Around line 1-17: The README currently contains only generic Vite+React
boilerplate; update it to describe this example as the "StablePay SDK Example",
briefly state its purpose (demonstrating StablePay SDK integration), list
features demonstrated (wallet connection/management, network & token selection,
transaction preparation/execution, success/error handling), add Getting Started
steps (npm install, npm run dev) and Usage notes that point to the integration
code in src/App.jsx (importing/configuring the StablePay widget, handling
transaction callbacks, managing wallet state); keep the existing note about the
React compiler and plugin links but replace template-specific text with these
example-specific instructions and a short Features/Usage section.In
@stablepay-sdk/src/widget/Dialog.jsx:
- Line 13: In the Dialog component replace the non-semantic
StablePaywith a proper heading element
(e.g.StablePay
) so the title retains
document/assistive heading semantics; keep the same className
(styles.stablepayTitle) and styling, and ensure the Dialog component still meets
any aria-labelledby usage if present.</details> <details> <summary>🪄 Autofix (Beta)</summary> Fix all unresolved CodeRabbit comments on this PR: - [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended) - [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes </details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: defaults **Review profile**: CHILL **Plan**: Pro **Run ID**: `67180db3-9253-4741-bfa4-8fc1e58945d4` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between a254fa62d912f352b543ba2811a03f3fdf213b1a and 4a3df35a6d15313a8009d388a64ac228322c1ff0. </details> <details> <summary>⛔ Files ignored due to path filters (12)</summary> * `stablepay-sdk/dist/esm/index.js` is excluded by `!**/dist/**` * `stablepay-sdk/dist/esm/styles.css` is excluded by `!**/dist/**` * `stablepay-sdk/dist/umd/index.js` is excluded by `!**/dist/**` * `stablepay-sdk/dist/umd/index.js.map` is excluded by `!**/dist/**`, `!**/*.map` * `stablepay-sdk/dist/umd/styles.css` is excluded by `!**/dist/**` * `stablepay-sdk/example/package-lock.json` is excluded by `!**/package-lock.json` * `stablepay-sdk/example/public/favicon.svg` is excluded by `!**/*.svg` * `stablepay-sdk/example/public/icons.svg` is excluded by `!**/*.svg` * `stablepay-sdk/example/src/assets/hero.png` is excluded by `!**/*.png` * `stablepay-sdk/example/src/assets/react.svg` is excluded by `!**/*.svg` * `stablepay-sdk/example/src/assets/vite.svg` is excluded by `!**/*.svg` * `stablepay-sdk/package-lock.json` is excluded by `!**/package-lock.json` </details> <details> <summary>📒 Files selected for processing (16)</summary> * `stablepay-sdk/example/.gitignore` * `stablepay-sdk/example/README.md` * `stablepay-sdk/example/eslint.config.js` * `stablepay-sdk/example/index.html` * `stablepay-sdk/example/package.json` * `stablepay-sdk/example/src/App.css` * `stablepay-sdk/example/src/App.jsx` * `stablepay-sdk/example/src/index.css` * `stablepay-sdk/example/src/main.jsx` * `stablepay-sdk/example/vite.config.js` * `stablepay-sdk/examples/index.txt` * `stablepay-sdk/src/core/Transaction.js` * `stablepay-sdk/src/styles/PricingCard.css` * `stablepay-sdk/src/widget/Dialog.jsx` * `stablepay-sdk/src/widget/TokenDropdown.jsx` * `stablepay-sdk/src/widget/TransactionReview.jsx` </details> <details> <summary>💤 Files with no reviewable changes (1)</summary> * stablepay-sdk/examples/index.txt </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| "dependencies": { | ||
| "ethers": "^6.16.0", | ||
| "react": "^19.2.6", | ||
| "react-dom": "^19.2.6", | ||
| "stablepay-sdk": "file:..", | ||
| "viem": "^2.52.2" | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if ethers is actually imported/used in the example app source
rg -n --type=js --type=jsx -g 'stablepay-sdk/example/src/**' "from ['\"]ethers['\"]|require\(['\"]ethers['\"]"Repository: DjedAlliance/StablePay
Length of output: 94
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate example source (and fall back safely if path differs)
if [ -d "stablepay-sdk/example/src" ]; then
SRC_DIR="stablepay-sdk/example/src"
else
echo "ERROR: stablepay-sdk/example/src not found" >&2
exit 1
fi
# Search for any direct import/require usage of ethers in the example source
rg -n --hidden --no-ignore -S \
--glob '*.js' --glob '*.jsx' --glob '*.ts' --glob '*.tsx' \
"from ['\"]ethers['\"]|require\(\s*['\"]ethers['\"]\s*\)|\bethers\b" \
"$SRC_DIR" || trueRepository: DjedAlliance/StablePay
Length of output: 48
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect whether stablepay-sdk declares ethers as a (peer) dependency that the example should provide
if [ -f "stablepay-sdk/package.json" ]; then
echo "=== stablepay-sdk/package.json (relevant fields) ==="
node -e "
const fs=require('fs');
const p=JSON.parse(fs.readFileSync('stablepay-sdk/package.json','utf8'));
const pick=(obj)=>obj&&obj.ethers?{ethers:obj.ethers}:undefined;
console.log('dependencies:', pick(p.dependencies));
console.log('peerDependencies:', pick(p.peerDependencies));
console.log('devDependencies:', pick(p.devDependencies));
"
else
echo "stablepay-sdk/package.json not found" >&2
fi
echo "=== stablepay-sdk/example/package.json (dependencies) ==="
node -e "
const fs=require('fs');
const p=JSON.parse(fs.readFileSync('stablepay-sdk/example/package.json','utf8'));
console.log(p.dependencies||{});
"Repository: DjedAlliance/StablePay
Length of output: 375
🏁 Script executed:
#!/bin/bash
set -euo pipefail
SRC_DIR="stablepay-sdk/example/src"
if [ ! -d "$SRC_DIR" ]; then
echo "ERROR: $SRC_DIR not found" >&2
exit 1
fi
echo "=== ethers usage in example/src ==="
MATCHES="$(rg -n --hidden --no-ignore -S \
--glob '*.js' --glob '*.jsx' --glob '*.ts' --glob '*.tsx' \
"from ['\"]ethers['\"]|require\(\s*['\"]ethers['\"]\s*\)|\bethers\b" \
"$SRC_DIR" || true)"
if [ -z "$MATCHES" ]; then
echo "(no direct ethers imports/requires/usages found)"
else
echo "$MATCHES"
fi
echo
echo "=== ethers usage in stablepay-sdk library (best-effort) ==="
# Find likely source roots for the SDK within stablepay-sdk
# - prefer 'src' if exists; otherwise search JS/TS files under stablepay-sdk excluding example/
if [ -d "stablepay-sdk/src" ]; then
LIB_DIR="stablepay-sdk/src"
else
LIB_DIR="stablepay-sdk"
fi
MATCHES2="$(rg -n --hidden --no-ignore -S \
--glob '*.js' --glob '*.jsx' --glob '*.ts' --glob '*.tsx' \
"\bethers\b" \
--glob '!stablepay-sdk/example/**' \
"$LIB_DIR" || true)"
if [ -z "$MATCHES2" ]; then
echo "(no ethers word found in stablepay-sdk library sources scanned)"
else
echo "$MATCHES2" | head -n 80
echo "… (truncated)"
fiRepository: DjedAlliance/StablePay
Length of output: 276
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== All occurrences of word 'ethers' under stablepay-sdk (excluding node_modules), first 80 lines ==="
rg -n --hidden --no-ignore -S "\bethers\b" stablepay-sdk \
--glob '!**/node_modules/**' \
--glob '!**/dist/**' \
--glob '!**/build/**' \
--glob '!**/.next/**' \
| head -n 80 || true
echo
echo "=== package.json files under stablepay-sdk that mention ethers (showing full matching lines) ==="
rg -n --hidden --no-ignore -S "ethers" stablepay-sdk \
--glob '**/package.json' \
--glob '!**/node_modules/**' \
--glob '!**/dist/**' \
--glob '!**/build/**' \
|| trueRepository: DjedAlliance/StablePay
Length of output: 1053
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== All occurrences of word 'ethers' under stablepay-sdk (including dist/build if present), excluding node_modules, first 80 lines ==="
rg -n --hidden --no-ignore -S "\bethers\b" stablepay-sdk \
--glob '!**/node_modules/**' \
| head -n 80 || trueRepository: DjedAlliance/StablePay
Length of output: 925
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Search for `@ethersproject` usage under stablepay-sdk (excluding node_modules) ==="
rg -n --hidden --no-ignore -S "`@ethersproject`" stablepay-sdk \
--glob '!**/node_modules/**' \
|| true
echo
echo "=== Search for common ethers-style symbols under stablepay-sdk (excluding node_modules) ==="
rg -n --hidden --no-ignore -S "\bJsonRpcProvider\b|\bWeb3Provider\b|\bBrowserProvider\b|\bContract\b" stablepay-sdk \
--glob '!**/node_modules/**' \
|| trueRepository: DjedAlliance/StablePay
Length of output: 9850
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== viem usage in example/src (imports/usages) ==="
rg -n --hidden --no-ignore -S \
--glob '*.js' --glob '*.jsx' --glob '*.ts' --glob '*.tsx' \
"\bviem\b|from ['\"]viem['\"]|require\(\s*['\"]viem['\"]\s*\)" \
stablepay-sdk/example/src || true
echo
echo "=== Non-example package.json files under stablepay-sdk (look for ethers/peerDeps) ==="
# List package.json (excluding example)
find stablepay-sdk -name package.json -not -path "*/example/*" | sort > /tmp/pkgjsons.txt
cat /tmp/pkgjsons.txt | sed -n '1,50p'
echo
echo "=== package.json lines containing ethers/peerDependencies for non-example packages ==="
# Search for ethers/peerDependencies only in those package.json files
if [ -s /tmp/pkgjsons.txt ]; then
rg -n --hidden --no-ignore -S "ethers|peerDependencies" -f /tmp/pkgjsons.txt --no-mmap || true
fiRepository: DjedAlliance/StablePay
Length of output: 401
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== stablepay-sdk/package.json (full) ==="
cat stablepay-sdk/package.json
echo
echo "=== viem usage in stablepay-sdk (excluding example/, node_modules), first 80 matches ==="
rg -n --hidden --no-ignore -S "\bviem\b|from ['\"]viem['\"]|require\(\s*['\"]viem['\"]\s*\)" stablepay-sdk \
--glob '!stablepay-sdk/example/**' \
--glob '!**/node_modules/**' \
| head -n 80 || true
echo
echo "=== ethers usage in stablepay-sdk (excluding example/, node_modules), first 80 matches ==="
rg -n --hidden --no-ignore -S "\bethers\b|from ['\"]ethers['\"]|require\(\s*['\"]ethers['\"]\s*\)" stablepay-sdk \
--glob '!stablepay-sdk/example/**' \
--glob '!**/node_modules/**' \
| head -n 80 || true
echo
echo "=== List all package.json under stablepay-sdk excluding example, and show ethers/viem-related dependency keys ==="
find stablepay-sdk -name package.json -not -path "*/example/*" -print | sort > /tmp/pkgjsons.txt
if [ -s /tmp/pkgjsons.txt ]; then
while IFS= read -r f; do
echo "--- $f ---"
node -e "
const fs=require('fs');
const p=JSON.parse(fs.readFileSync('$f','utf8'));
const keys=['dependencies','peerDependencies','devDependencies','optionalDependencies'];
for (const k of keys){
if (p[k] && (p[k].ethers || p[k].viem)){
console.log(k, {ethers:p[k].ethers, viem:p[k].viem});
}
}
"
done < /tmp/pkgjsons.txt
else
echo "(no non-example package.json found)"
fiRepository: DjedAlliance/StablePay
Length of output: 50379
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== ethers usage anywhere in stablepay-sdk/example (excluding node_modules & package-lock.json) ==="
rg -n --hidden --no-ignore -S "\bethers\b|from ['\"]ethers['\"]|require\(\s*['\"]ethers['\"]\s*\)" stablepay-sdk/example \
--glob '!**/node_modules/**' \
--glob '!**/package-lock.json' \
|| true
echo
echo "=== viem usage anywhere in stablepay-sdk/example (excluding node_modules & package-lock.json), first 40 matches ==="
rg -n --hidden --no-ignore -S "\bviem\b|from ['\"]viem['\"]|require\(\s*['\"]viem['\"]\s*\)" stablepay-sdk/example \
--glob '!**/node_modules/**' \
--glob '!**/package-lock.json' \
| head -n 40 || trueRepository: DjedAlliance/StablePay
Length of output: 406
Remove unused ethers dependency from stablepay-sdk/example [minor]
stablepay-sdk/example/package.jsondeclaresethers, but there are noethersimports/usages instablepay-sdk/example/src(it only appears in the example manifest/lockfile).- The SDK/widget code uses
viemfor wallet interactions (e.g.,stablepay-sdk/src/widget/TransactionReview.jsx), so the example app shouldn’t needethersdirectly. - Drop
ethersfromstablepay-sdk/example/package.json(and updatepackage-lock.json) to avoid dependency bloat/confusion.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@stablepay-sdk/example/package.json` around lines 12 - 18, Remove the unused
ethers dependency from the example app by deleting the "ethers" entry in
stablepay-sdk/example/package.json and then regenerate the lockfile
(package-lock.json) by running the package manager (e.g., npm install) inside
stablepay-sdk/example; ensure no code in stablepay-sdk/example/src imports
"ethers" (the widget uses viem, see
stablepay-sdk/src/widget/TransactionReview.jsx) before committing the updated
package.json and package-lock.json.
| const isConnectionError = error.code === -32603 || error.code === 4001 || error.code === -32005 || (error.message && (error.message.includes('CONNECTION ERROR') || error.message.includes('ERR_NAME_NOT_RESOLVED'))); | ||
| if (isConnectionError) { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the exact lines in Transaction.js
sed -n '1,120p' stablepay-sdk/src/core/Transaction.js | nl -ba | sed -n '40,95p'
# Show the rest around the error handling (if present)
rg -n "isConnectionError|error\.code === 4001|CONNECTION ERROR|ERR_NAME_NOT_RESOLVED" stablepay-sdk/src/core/Transaction.js
# Find all occurrences of "=== 4001" across the repo
rg -n "code === 4001" stablepay-sdk/src | head -n 50
# Inspect the referenced wallet/transaction UI files where 4001 is likely handled
ls -la stablepay-sdk/src/contexts || true
ls -la stablepay-sdk/src/widget || true
sed -n '1,220p' stablepay-sdk/src/contexts/WalletContext.jsx | nl -ba | sed -n '1,220p'
sed -n '200,340p' stablepay-sdk/src/widget/TransactionReview.jsx | nl -ba | sed -n '200,340p'
# Search for any docs/mapping of error codes for web3/eth provider
rg -n "4001|UserRejectedRequestError|User denied" stablepay-sdk/src stablepay-sdk/package.json package.json || trueRepository: DjedAlliance/StablePay
Length of output: 109
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Inspect Transaction.js around the relevant lines (no nl)
echo "=== Transaction.js around line 56-57 ==="
sed -n '45,80p' stablepay-sdk/src/core/Transaction.js | cat -n
echo "=== Exact occurrences of 4001 / connection-error markers in Transaction.js ==="
rg -n "isConnectionError|error\.code\s*===\s*4001|CONNECTION ERROR|ERR_NAME_NOT_RESOLVED" stablepay-sdk/src/core/Transaction.js
# 2) Find all uses of code === 4001 in the repo (for context consistency)
echo "=== All occurrences of \"code === 4001\" in stablepay-sdk/src ==="
rg -n "code\s*===\s*4001" stablepay-sdk/src | head -n 50
# 3) Inspect the referenced wallet/transaction UI files for how 4001 is classified
echo "=== WalletContext.jsx around switchToNetwork / sendTransaction error handling ==="
sed -n '1,260p' stablepay-sdk/src/contexts/WalletContext.jsx | cat -n
echo "=== TransactionReview.jsx around error handling area (near ~246) ==="
sed -n '200,340p' stablepay-sdk/src/widget/TransactionReview.jsx | cat -n
# 4) Check any error-code mapping/docs (quick grep)
echo "=== Mentions of 4001/UserRejectedRequestError in repo ==="
rg -n "4001|UserRejectedRequestError|User denied|rejected" stablepay-sdk/src | head -n 100Repository: DjedAlliance/StablePay
Length of output: 20925
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Transaction.js (top portion) ==="
sed -n '1,120p' stablepay-sdk/src/core/Transaction.js | cat -n
echo "=== Check if Transaction.js references window.ethereum ==="
rg -n "window\.ethereum|eth_requestAccounts|wallet_switchEthereumChain|wallet_addEthereumChain|UserRejectedRequestError" stablepay-sdk/src/core/Transaction.js || true
echo "=== Check what calls are inside the init try block (look for web3 init / provider calls) ==="
# Print the section from the start of the likely init/constructor around where the catch we saw is located
sed -n '120,220p' stablepay-sdk/src/core/Transaction.js | cat -n
echo "=== Search for 'RPC endpoint' wording to find any message templates ==="
rg -n "Failed to connect to .* RPC endpoint" stablepay-sdk/src/core/Transaction.jsRepository: DjedAlliance/StablePay
Length of output: 6398
Fix inconsistent handling of error code 4001
stablepay-sdk/src/core/Transaction.js includes error.code === 4001 in isConnectionError, which throws an RPC-connection failure message. In the rest of the SDK, 4001 is treated as user rejection (stablepay-sdk/src/contexts/WalletContext.jsx, stablepay-sdk/src/widget/TransactionReview.jsx), so this classification is inconsistent and can mislead if 4001 ever propagates here. Remove 4001 from the connection-error bucket (or handle it separately as user rejection).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@stablepay-sdk/src/core/Transaction.js` around lines 56 - 57, The
isConnectionError check in Transaction.js incorrectly treats error.code === 4001
as an RPC connection failure; remove 4001 from the isConnectionError condition
in the isConnectionError declaration inside the Transaction handling logic and
instead handle error.code === 4001 as a user-rejection case (consistent with
WalletContext.jsx and TransactionReview.jsx), e.g., branch separately to
return/throw a user-rejection error or status so 4001 is no longer classified as
a connection error.
| <button | ||
| className={styles.walletButton} | ||
| onClick={() => window.open('https://metamask.io/download/', '_blank')} | ||
| > |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="stablepay-sdk/src/widget/TransactionReview.jsx"
# Basic sanity: ensure file exists and show relevant lines around 90-120
if [ ! -f "$file" ]; then
echo "Missing file: $file" >&2
exit 1
fi
echo "---- Context ($file:80-130) ----"
nl -ba "$file" | sed -n '80,130p'
echo
echo "---- Search for window.open( in repo ----"
rg -n "window\.open\(" stablepay-sdk/src/widget/TransactionReview.jsx stablepay-sdk/src || trueRepository: DjedAlliance/StablePay
Length of output: 202
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="stablepay-sdk/src/widget/TransactionReview.jsx"
# Basic sanity: ensure file exists and show relevant lines around 90-120
if [ ! -f "$file" ]; then
echo "Missing file: $file" >&2
exit 1
fi
echo "---- Context ($file:80-130) ----"
nl -ba "$file" | sed -n '80,130p'
echo
echo "---- Search for window.open( in repo ----"
rg -n "window\.open\(" stablepay-sdk/src || true
echo
echo "---- Search for rel/noopener patterns in JSX anchor tags ----"
rg -n "rel\s*=\s*{?.*noopener|noopener|noreferrer" stablepay-sdk/src || trueRepository: DjedAlliance/StablePay
Length of output: 202
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="stablepay-sdk/src/widget/TransactionReview.jsx"
if [ ! -f "$file" ]; then
echo "Missing file: $file" >&2
exit 1
fi
echo "---- Context ($file:95-110) ----"
sed -n '95,110p' "$file" | awk '{printf "%d:%s\n", NR+94, $0}'
echo
echo "---- Search for window.open( in TransactionReview.jsx ----"
rg -n "window\.open\(" "$file" || true
echo
echo "---- Search for window.open( in stablepay-sdk/src ----"
rg -n "window\.open\(" stablepay-sdk/src || true
echo
echo "---- Search for noopener/noreferrer usage in stablepay-sdk/src ----"
rg -n "noopener|noreferrer|rel\s*=\s*['\"]noopener|rel\s*=\s*['\"]noreferrer|noopener,noreferrer" stablepay-sdk/src || trueRepository: DjedAlliance/StablePay
Length of output: 1252
Harden external link opening against tabnabbing.
window.open(..., '_blank') at the click handler lacks noopener/noreferrer, allowing the opened page to control window.opener. Add the flags via the third argument.
Suggested patch
- onClick={() => window.open('https://metamask.io/download/', '_blank')}
+ onClick={() => window.open('https://metamask.io/download/', '_blank', 'noopener,noreferrer')}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button | |
| className={styles.walletButton} | |
| onClick={() => window.open('https://metamask.io/download/', '_blank')} | |
| > | |
| <button | |
| className={styles.walletButton} | |
| onClick={() => window.open('https://metamask.io/download/', '_blank', 'noopener,noreferrer')} | |
| > |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@stablepay-sdk/src/widget/TransactionReview.jsx` around lines 101 - 104, The
button's onClick uses window.open(url, '_blank') which is vulnerable to
tabnabbing; update the click handler in TransactionReview.jsx to call
window.open('https://metamask.io/download/', '_blank', 'noopener,noreferrer')
(or alternatively set the returned window's opener to null) so the opened page
cannot access window.opener.
| let builtTx; | ||
|
|
||
| if (selectedToken.key === "native") { | ||
| const UI = "0x0232556C83791b8291E9b23BfEa7d67405Bd9839"; |
There was a problem hiding this comment.
Is there a reason this address is hardcoded? Would it be better to source it from a configuration/constants file so it can be updated more easily and avoids chain-specific values being embedded in the logic?
There was a problem hiding this comment.
@Atharva0506 The UI variable is the address of the stablepay treasury; basically, any transaction done through this interface will pay some fee to this address. It is meant to be hardcoded and not configured by a developer as an environment variable.
Addressed Issues:
Fixes #60 and #62
Screenshots/Recordings:
Case 1: User has a wallet
has_wallet.mp4
Case 2: User has no wallet
no_wallet.mp4
Additional Notes:
Description
This Pull Request introduces a comprehensive example application to demonstrate SDK integration and significantly improves the UI/UX and validation flow of the StablePay SDK widgets.
Why a new example website?
A fully fledged example website repo exists (https://github.com/DjedAlliance/StablePay-MerchantWebsiteDemo), but it does not update stable-sdk in real time. We need to update stablepay-sdk on npm to get the latest build in that example website. I have made this example website within the SDK to show widgets and a user flow that updates automatically with every local SDK build.
Changes made:
Checklist
AI Usage Disclosure
Check one of the checkboxes below:
Summary by CodeRabbit
New Features
Bug Fixes
UI/Style
Refactor