Skip to content

chore: pay method rework#4669

Merged
lukaisailovic merged 7 commits intomainfrom
chore/improve-pay-connection-handling
Jul 18, 2025
Merged

chore: pay method rework#4669
lukaisailovic merged 7 commits intomainfrom
chore/improve-pay-connection-handling

Conversation

@lukaisailovic
Copy link
Copy Markdown
Collaborator

@lukaisailovic lukaisailovic commented Jul 17, 2025

Description

Changed the pay method to handle the success/error subscription internally and export single pay method that will resolve once the payment is completed.

Before:

  function handleSuccess(resultData: PayResult) {
    toast({
      title: 'Transaction successful',
      description: resultData,
      type: 'success'
    })
  }

  function handleError(errorData: AppKitPayErrorMessage) {
    toast({
      title: 'Transaction failed',
      description: errorData,
      type: 'error'
    })
  }

  const { open, isPending } = usePay({
    onSuccess: handleSuccess,
    onError: handleError
  })
  

 await open({
    recipient: paymentDetails.recipient,
    amount: paymentDetails.amount,
    paymentAsset: paymentDetails.asset
})

After:

const result = await pay({
  recipient: paymentDetails.recipient,
  amount: paymentDetails.amount,
  paymentAsset: paymentDetails.asset,
});

if (result.success) {
  toast({ title: "Payment Succeeded", type: "success" });
} else {
  toast({ title: "Payment Failed", type: "error" });
}

Tehnical

isSettled is added because we react on multiple different state subscriptions. In order to avoid race conditions, we introduce additional variable in case multiple subscriptions trigger the handler

Additionally this handles

Type of change

  • Chore (non-breaking change that addresses non-functional tasks, maintenance, or code quality improvements)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Associated Issues

For Linear issues: Closes APKT-xxx
For GH issues: closes #...

Showcase (Optional)

If there is a UI change include the screenshots with before and after state.
If new feature is being introduced, include the link to demo recording.

Checklist

  • Code in this PR is covered by automated tests (Unit tests, E2E tests)
  • My changes generate no new warnings
  • I have reviewed my own code
  • I have filled out all required sections
  • I have tested my changes on the preview link
  • Approver of this PR confirms that the changes are tested on the preview link

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Jul 17, 2025

🦋 Changeset detected

Latest commit: da9d9b8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 23 packages
Name Type
@reown/appkit-pay Patch
@reown/appkit Patch
@reown/appkit-adapter-bitcoin Patch
@reown/appkit-adapter-ethers Patch
@reown/appkit-adapter-ethers5 Patch
@reown/appkit-adapter-solana Patch
@reown/appkit-adapter-wagmi Patch
@reown/appkit-cdn Patch
@reown/appkit-experimental Patch
@reown/appkit-testing Patch
@reown/appkit-common Patch
@reown/appkit-ui Patch
@reown/appkit-controllers Patch
@reown/appkit-core Patch
@reown/appkit-utils Patch
@reown/appkit-scaffold-ui Patch
@reown/appkit-polyfills Patch
@reown/appkit-wallet Patch
@reown/appkit-siwe Patch
@reown/appkit-siwx Patch
@reown/appkit-wallet-button Patch
@reown/appkit-cli Patch
@reown/appkit-codemod Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel bot commented Jul 17, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
appkit-basic-html ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 17, 2025 7:30pm
appkit-demo ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 17, 2025 7:30pm
appkit-gallery ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 17, 2025 7:30pm
appkit-laboratory ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 17, 2025 7:30pm
10 Skipped Deployments
Name Status Preview Comments Updated (UTC)
appkit-basic-example ⬜️ Ignored (Inspect) Jul 17, 2025 7:30pm
appkit-basic-sign-client-example ⬜️ Ignored (Inspect) Jul 17, 2025 7:30pm
appkit-basic-up-example ⬜️ Ignored (Inspect) Jul 17, 2025 7:30pm
appkit-ethers5-bera ⬜️ Ignored (Inspect) Jul 17, 2025 7:30pm
appkit-nansen-demo ⬜️ Ignored (Inspect) Jul 17, 2025 7:30pm
appkit-vue-solana ⬜️ Ignored (Inspect) Jul 17, 2025 7:30pm
appkit-wagmi-cdn-example ⬜️ Ignored (Inspect) Jul 17, 2025 7:30pm
ethereum-provider-wagmi-example ⬜️ Ignored (Inspect) Jul 17, 2025 7:30pm
next-wagmi-solana-bitcoin-example ⬜️ Ignored (Inspect) Jul 17, 2025 7:30pm
vue-wagmi-example ⬜️ Ignored (Inspect) Jul 17, 2025 7:30pm

cursor[bot]

This comment was marked as outdated.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jul 17, 2025

Warnings
⚠️

🔑 Potential High‑entropy string detected in apps/laboratory/src/components/AppKitPay.tsx (line 69): EPjFWdd5AufqSSqeM2qN...

⚠️

🔑 Potential High‑entropy string detected in apps/laboratory/src/components/AppKitPay.tsx (line 444): 0x833589fcd6edb6e08f...

Generated by 🚫 dangerJS against da9d9b8

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jul 17, 2025

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 77.63% 30821 / 39699
🔵 Statements 77.63% 30821 / 39699
🔵 Functions 68.87% 2534 / 3679
🔵 Branches 84.29% 6432 / 7630
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/pay/src/controllers/PayController.ts 87.6% 82.79% 85.71% 87.6% 102-103, 163-164, 198, 298-299, 302-304, 308-320, 330-331, 337-338, 343-344, 349-350, 353-354, 396-404, 422-423, 535-548, 557-558
Generated in workflow #13465 for commit da9d9b8 by the Vitest Coverage Report Action

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Payment Button Fails to Disable During Processing

The "Open Pay Modal" button is no longer disabled or shows a loading state during payment processing. This allows users to trigger multiple concurrent pay() calls, creating a race condition where new calls reset the PayController state, causing earlier payment attempts to hang or fail. Previously, the button was disabled using isPending state and displayed a spinner.

apps/laboratory/src/components/AppKitPay.tsx#L501-L504

<Stack spacing="4">
<Button onClick={handleOpenPay} width="full">
Open Pay Modal
</Button>

Fix in CursorFix in Web


Bug: Async Function Call Without Await

The async handlePayment() function is called without await within the ConnectionController.subscribeKey and AccountController.subscribeKey subscription handlers. This change from the original implementation, which correctly used await, can lead to unhandled promise rejections if handlePayment() throws an error.

packages/pay/src/controllers/PayController.ts#L300-L321

ConnectionController.subscribeKey('connections', connections => {
if (connections.size > 0) {
this.handlePayment()
}
})
AccountController.subscribeKey('caipAddress', caipAddress => {
const hasWcConnection = ConnectionController.hasAnyConnection(
ConstantsUtil.CONNECTOR_ID.WALLET_CONNECT
)
if (caipAddress) {
// WalletConnect connections sometimes fail down the line due to state not being updated atomically
if (hasWcConnection) {
setTimeout(() => {
this.handlePayment()
}, 100)
} else {
this.handlePayment()
}
}
})

Fix in CursorFix in Web


Bug: Payment API Error Handling Inconsistency

The pay function exhibits inconsistent error handling: it rejects the promise on timeout, but resolves with { success: false } for all other payment failures. To maintain API consistency, timeouts should also resolve with { success: false, error: 'Payment timeout' }.

packages/pay/src/client.ts#L38-L46

const timeoutId = setTimeout(() => {
if (isSettled) {
return
}
isSettled = true
cleanup()
reject(new AppKitPayError(AppKitPayErrorCodes.GENERIC_PAYMENT_ERROR, 'Payment timeout'))
}, timeoutMs)

Fix in CursorFix in Web


Bug: Unhandled Promise Rejections in Payment Handling

The handleOpenPay function lacks a try-catch block around the await pay call. Although pay returns a result object for most outcomes, it can still reject its promise (e.g., due to timeouts, initialization failures, or other critical errors). This omission results in unhandled promise rejections, leading to application crashes or silent failures without appropriate error messages being displayed to the user.

apps/laboratory/src/components/AppKitPay.tsx#L183-L204

async function handleOpenPay() {
if (!paymentDetails.recipient) {
toast({ title: 'Missing Recipient', description: 'Please enter a recipient address.' })
return
}
const result = await pay({
recipient: paymentDetails.recipient,
amount: paymentDetails.amount,
paymentAsset: paymentDetails.asset
})
if (result.success) {
toast({ title: 'Payment Succeeded', description: `Tx: ${result.result}`, type: 'success' })
} else {
toast({
title: 'Payment Failed',
description: result.error ?? 'Unknown error',
type: 'error'
})
}

Fix in CursorFix in Web


Was this report helpful? Give feedback by reacting with 👍 or 👎

@lukaisailovic lukaisailovic added this pull request to the merge queue Jul 18, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jul 18, 2025
@lukaisailovic lukaisailovic added this pull request to the merge queue Jul 18, 2025
Merged via the queue into main with commit 61292da Jul 18, 2025
59 of 60 checks passed
@lukaisailovic lukaisailovic deleted the chore/improve-pay-connection-handling branch July 18, 2025 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants