-
Notifications
You must be signed in to change notification settings - Fork 574
[MNY-131] Add Pay Modal integration in useSendAndConfirmTransaction hook #7946
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
[MNY-131] Add Pay Modal integration in useSendAndConfirmTransaction hook #7946
Conversation
🦋 Changeset detectedLatest commit: 597431e The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
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 |
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds a web-specific useSendAndConfirmTransaction hook that composes useSendTransaction with on-chain confirmation and Pay Modal integration, renames the core hook export to useSendAndConfirmTransactionCore, updates react exports, augments JSDoc, and wires pay-modal metadata through several prebuilt UI buttons. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor App as App Component
participant Hook as useSendAndConfirmTransaction (web)
participant Send as useSendTransaction
participant Pay as Pay Modal
participant RPC as Provider/Chain
participant Conf as waitForReceipt
App->>Hook: mutateAsync(transaction)
activate Hook
Hook->>Send: mutateAsync(transaction, { payModal: ... })
alt Insufficient funds
Send->>Pay: Open Pay Modal (metadata)
Note right of Pay: User tops up or cancels
Pay-->>Send: Proceed or error
end
Send->>RPC: submit tx
Send-->>Hook: tx hash
Hook->>Conf: waitForReceipt(tx hash)
Conf-->>Hook: confirmed receipt
Hook-->>App: TransactionReceipt
deactivate Hook
alt Error path
Send-->>App: Error
Conf-->>App: Error
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Assessment against linked issues
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
size-limit report 📦
|
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: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
packages/thirdweb/src/tokens/create-token.ts (1)
19-33
: Make this sync, fix event name in error, and add TSDoc with precise return type
- Function is
async
withoutawait
; return a plain value to avoid unnecessary Promise wrapping.- Error mentions “AssetCreated” but the decoded event is
Created
; message should match.- Public API needs TSDoc (per repo guidelines). Also narrow return type to
Address
instead of generic hex.Diff within this block:
-export async function getTokenAddressFromReceipt(receipt: TransactionReceipt) { +/** + * Extract the created ERC20 token address from a token-creation transaction receipt. + * + * @param receipt The transaction receipt returned from sending the prepared create-token transaction. + * @returns The created token contract address. + * @example + * const tx = await sendAndConfirmTx(prepareCreateToken(opts)); + * const tokenAddress = getTokenAddressFromReceipt(tx); + */ +export function getTokenAddressFromReceipt(receipt: TransactionReceipt) { const assetEvent = createdEvent(); const decodedEvent = parseEventLogs({ events: [assetEvent], logs: receipt.logs, }); if (decodedEvent.length === 0 || !decodedEvent[0]) { throw new Error( - `No AssetCreated event found in transaction: ${receipt.transactionHash}`, + `No Created event found in transaction: ${receipt.transactionHash}`, ); } - return decodedEvent[0]?.args.asset; + return decodedEvent[0].args.asset; }Additionally, import and use the precise type:
// add to imports import type { Address } from "viem";And, if desired, annotate the return type explicitly:
export function getTokenAddressFromReceipt(receipt: TransactionReceipt): Address { ... }packages/thirdweb/src/exports/react.ts (1)
70-76
: Also export the config type for the new hook from the public surface.Consumers will need the config type when using the hook. Please re-export it to keep the API consistent with other transaction hooks.
Apply this diff:
export type { SendTransactionConfig, SendTransactionPayModalConfig, } from "../react/core/hooks/transaction/useSendTransaction.js"; +export type { + SendAndConfirmTransactionConfig, +} from "../react/web/hooks/transaction/useSendAndConfirmTransaction.js";packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/index.tsx (1)
139-143
: TransactionButton always receives an object, so payModal: false is ignored.This unintentionally re-enables the modal. Preserve false.
Apply this diff:
- payModal={{ - metadata: defaultPayModalMetadata || payMetadata, - ...payModal, - }} + payModal={ + payModal === false + ? false + : { + metadata: defaultPayModalMetadata || payMetadata, + ...payModal, + } + }packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx (2)
181-184
: TransactionButton always receives an object, so payModal: false is ignored.Preserve false when the user disables the modal.
Apply this diff:
- payModal={{ - metadata: defaultPayModalMetadata || payMetadata, - ...payModal, - }} + payModal={ + payModal === false + ? false + : { + metadata: defaultPayModalMetadata || payMetadata, + ...payModal, + } + }
137-158
: Quantity logic bug for ERC1155: overwrites user input and allows 0n.
- _quantity is set from quantity and then overwritten with listing.quantity.
- 0n passes validation though the error says “at least 1n”.
Fix validation and only default when quantity is not provided.
Apply this diff:
- let _quantity = 1n; - // For ERC721 the quantity should always be 1n. We throw an error if user passes a different props - if (listing.asset.type === "ERC721") { - if (typeof quantity === "bigint" && (quantity !== 1n || quantity < 0n)) { - throw new Error( - "Invalid quantity. This is an ERC721 listing & quantity is always `1n`", - ); - } - } else if (listing.asset.type === "ERC1155") { - if (typeof quantity === "bigint") { - if (quantity > listing.quantity) { - throw new Error( - `quantity exceeds available amount. Available: ${listing.quantity.toString()}`, - ); - } - if (quantity < 0n) { - throw new Error("Invalid quantity. Should be at least 1n"); - } - _quantity = quantity; - } - _quantity = listing.quantity; - } + let _quantity: bigint; + // ERC721 must always be 1 + if (listing.asset.type === "ERC721") { + if (typeof quantity === "bigint" && quantity !== 1n) { + throw new Error( + "Invalid quantity. This is an ERC721 listing & quantity must be `1n`", + ); + } + _quantity = 1n; + } else if (listing.asset.type === "ERC1155") { + if (typeof quantity === "bigint") { + if (quantity > listing.quantity) { + throw new Error( + `quantity exceeds available amount. Available: ${listing.quantity.toString()}`, + ); + } + if (quantity <= 0n) { + throw new Error("Invalid quantity. Should be at least 1n"); + } + _quantity = quantity; + } else { + _quantity = listing.quantity; + } + }
🧹 Nitpick comments (9)
packages/thirdweb/src/react/web/hooks/transaction/useSendTransaction.tsx (1)
96-121
: Doc examples: fix destructuring and call out gasless disables Pay Modal
- The snippets assign the hook return to
sendTx
, which reads like a function; previous examples use{ mutate: sendTx }
. Align for clarity.- Mention that
gasless: true
disables the Pay Modal even if configured.Apply:
@@ - * const sendTx = useSendTransaction({ + * const { mutate: sendTx } = useSendTransaction({ * payModal: { * theme: "light", * }, * }); @@ - * const sendTx = useSendTransaction({ + * const { mutate: sendTx } = useSendTransaction({ * payModal: false, * }); + * + * // Note: + * // If you enable `gasless`, the Pay Modal is automatically disabled.packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts (1)
8-10
: JSDoc header references the wrong hookText says “Configuration for the
useSendTransaction
hook.” This file is for “useSendAndConfirmTransaction”. Fix to avoid confusing generated docs.Suggested:
/** * Configuration for the `useSendAndConfirmTransaction` hook. */packages/thirdweb/src/tokens/create-token.ts (1)
35-69
: Add/ensure TSDoc for prepareCreateToken and tighten typesThis is a public surface. Add TSDoc with an
@example
that compiles and clarifies that sending is external (hook or action). Consider returning a typedPreparedTransaction
if available in your types to strengthen contracts.Example TSDoc:
/** * Prepare the ERC20 create-token transaction without sending it. * * Use the returned transaction with `useSendAndConfirmTransaction` (web/RN) or the * low-level `sendAndConfirmTransaction` action. * * @param options Parameters for token creation including init params, creator, and pool config. * @returns A prepared transaction ready to be sent. * @example * const tx = await prepareCreateToken(opts); * const { mutateAsync: sendAndConfirmTx } = useSendAndConfirmTransaction(); * const receipt = await sendAndConfirmTx(tx); * const tokenAddress = getTokenAddressFromReceipt(receipt); */packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx (1)
25-36
: Minor doc fixes.
- “users's” → “user's”
Apply this diff:
- * A hook to send a transaction and confirm the transaction with users's connected wallet + * A hook to send a transaction and confirm the transaction with the user's connected walletpackages/thirdweb/src/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.tsx (5)
91-98
: Use nullish coalescing for metadata to avoid overriding valid falsy values.
||
will replace valid falsy values (e.g., empty string). Prefer??
.- const { mutateAsync } = useSendAndConfirmTransaction({ - payModal: payModal - ? { - ...payModal, - metadata: payModal.metadata || payMetadata, - } - : undefined, - }); + const { mutateAsync } = useSendAndConfirmTransaction({ + payModal: payModal + ? { + ...payModal, + metadata: payModal.metadata ?? payMetadata, + } + : undefined, + });
178-183
: Ensure UI and mutation resolve metadata identically; use??
here too.Keeps parity with the hook config and avoids clobbering valid falsy metadata.
- payModal={{ - metadata: defaultPayModalMetadata || payMetadata, - ...payModal, - }} + payModal={{ + metadata: defaultPayModalMetadata ?? payMetadata, + ...payModal, + }}Optional: derive a single
resolvedPayModal
(via useMemo) and pass it to both the hook and TransactionButton to eliminate drift.
156-160
: Address comparison: prefer a canonical helper overtoLowerCase()
string ops.Use an address equality helper (e.g.,
isAddressEqual(a, b)
) if available to avoid locale/case pitfalls.- if ( - !isApproved && - tokenApproved.toLowerCase() !== - marketplaceContract.address.toLowerCase() - ) { + if (!isApproved && !isAddressEqual(tokenApproved, marketplaceContract.address)) {If no helper exists, consider normalizing via checksum utilities already used in the codebase.
84-90
: Query gating: prefer nullish check for readability and intent.
enabled: defaultPayModalMetadata == null
communicates “fetch only when missing,” and avoids accidental disablement if an empty value is ever passed.- enabled: !defaultPayModalMetadata, + enabled: defaultPayModalMetadata == null,
183-183
: Minor: pass the memoized function reference directly.Avoids recreating a lambda on each render.
- transaction={() => prepareTransaction()} + transaction={prepareTransaction}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (11)
.changeset/pretty-geese-win.md
(1 hunks)packages/thirdweb/src/exports/react.native.ts
(1 hunks)packages/thirdweb/src/exports/react.ts
(1 hunks)packages/thirdweb/src/exports/tokens.ts
(1 hunks)packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts
(1 hunks)packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx
(1 hunks)packages/thirdweb/src/react/web/hooks/transaction/useSendTransaction.tsx
(1 hunks)packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx
(2 hunks)packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/index.tsx
(2 hunks)packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.tsx
(2 hunks)packages/thirdweb/src/tokens/create-token.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}
: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/types
or localtypes.ts
barrels
Prefer type aliases over interface except for nominal shapes
Avoidany
andunknown
unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial
,Pick
, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Files:
packages/thirdweb/src/react/web/hooks/transaction/useSendTransaction.tsx
packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts
packages/thirdweb/src/exports/react.ts
packages/thirdweb/src/exports/react.native.ts
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/index.tsx
packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.tsx
packages/thirdweb/src/exports/tokens.ts
packages/thirdweb/src/tokens/create-token.ts
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
packages/thirdweb/src/react/web/hooks/transaction/useSendTransaction.tsx
packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts
packages/thirdweb/src/exports/react.ts
packages/thirdweb/src/exports/react.native.ts
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/index.tsx
packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.tsx
packages/thirdweb/src/exports/tokens.ts
packages/thirdweb/src/tokens/create-token.ts
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx
packages/thirdweb/src/exports/**
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/exports/**
: Export everything viaexports/
directory, grouped by feature in the SDK public API
Every public symbol must have comprehensive TSDoc with at least one@example
block that compiles and custom annotation tags (@beta
,@internal
,@experimental
)
Files:
packages/thirdweb/src/exports/react.ts
packages/thirdweb/src/exports/react.native.ts
packages/thirdweb/src/exports/tokens.ts
🧠 Learnings (4)
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/exports/react.native.ts : React Native specific exports are in `src/exports/react.native.ts`
Applied to files:
packages/thirdweb/src/exports/react.ts
packages/thirdweb/src/exports/react.native.ts
📚 Learning: 2025-06-17T18:30:52.976Z
Learnt from: MananTank
PR: thirdweb-dev/js#7356
File: apps/nebula/src/app/not-found.tsx:1-1
Timestamp: 2025-06-17T18:30:52.976Z
Learning: In the thirdweb/js project, the React namespace is available for type annotations (like React.FC) without needing to explicitly import React. This is project-specific configuration that differs from typical TypeScript/React setups.
Applied to files:
packages/thirdweb/src/exports/react.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
packages/thirdweb/src/exports/react.ts
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/index.tsx
📚 Learning: 2025-08-28T12:24:37.171Z
Learnt from: MananTank
PR: thirdweb-dev/js#7933
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx:0-0
Timestamp: 2025-08-28T12:24:37.171Z
Learning: In the token creation flow, the tokenAddress field in erc20Asset_poolMode is always initialized with nativeTokenAddress and is never undefined, so conditional checks for undefined tokenAddress are not needed.
Applied to files:
packages/thirdweb/src/tokens/create-token.ts
🧬 Code graph analysis (6)
packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts (1)
packages/thirdweb/src/exports/react.native.ts (1)
useSendAndConfirmTransactionCore
(62-62)
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/index.tsx (1)
packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx (1)
useSendAndConfirmTransaction
(89-104)
packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx (2)
packages/thirdweb/src/exports/react.ts (2)
useSendAndConfirmTransaction
(127-127)useSendTransaction
(128-128)packages/thirdweb/src/react/web/hooks/transaction/useSendTransaction.tsx (1)
useSendTransaction
(124-177)
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.tsx (2)
packages/thirdweb/src/exports/react.ts (1)
useSendAndConfirmTransaction
(127-127)packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx (1)
useSendAndConfirmTransaction
(89-104)
packages/thirdweb/src/tokens/create-token.ts (1)
packages/thirdweb/src/exports/tokens.ts (1)
getTokenAddressFromReceipt
(9-9)
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx (2)
packages/thirdweb/src/exports/react.ts (1)
useSendAndConfirmTransaction
(127-127)packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx (1)
useSendAndConfirmTransaction
(89-104)
⏰ 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). (3)
- GitHub Check: Unit Tests
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts (1)
57-78
: Rename to useSendAndConfirmTransactionCore looks goodThe symbol rename preserves the public API via re-exports; hook logic unchanged. No functional concerns here.
packages/thirdweb/src/tokens/create-token.ts (1)
45-46
: generateSalt enforces 32-byte salts; 31 bytes of entropy is correct
The helper always outputs a 32-byte value (1 byte flags + 31 bytes data), padding or hashing inputs to 62 hex chars and prepending the flag byte. PassingrandomBytes(31)
meets the contract’s expectations—no change required.packages/thirdweb/src/exports/react.ts (1)
127-127
: Switching the public export to the web hook looks correct.This aligns the web API with the new Pay Modal flow. Cross-platform parity is handled in react.native.ts.
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/index.tsx (1)
14-14
: Import path change to the web hook is correct.packages/thirdweb/src/exports/react.native.ts (1)
62-62
: RN export aliasing Core to the public name is correct.Keeps the RN API stable while web moves to the new composition.
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx (1)
12-12
: Import path change to the web hook is correct.packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.tsx (1)
17-17
: All useSendAndConfirmTransaction imports are updated correctly—no stale imports found.
packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx
Show resolved
Hide resolved
packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx
Outdated
Show resolved
Hide resolved
packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx
Show resolved
Hide resolved
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx
Outdated
Show resolved
Hide resolved
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/index.tsx
Outdated
Show resolved
Hide resolved
24db91b
to
c27b6d1
Compare
c27b6d1
to
bd66024
Compare
bd66024
to
ec2ece0
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #7946 +/- ##
==========================================
- Coverage 56.54% 56.53% -0.02%
==========================================
Files 904 904
Lines 58605 58623 +18
Branches 4142 4146 +4
==========================================
+ Hits 33141 33144 +3
- Misses 25358 25373 +15
Partials 106 106
🚀 New features to boost your workflow:
|
Merge activity
|
…ook (#7946) <!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR introduces a `Pay Modal` integration in the `useSendAndConfirmTransaction` hook, allowing users to handle insufficient funds by prompting them to purchase more. It also renames the hook and updates related components to utilize the new configuration. ### Detailed summary - Renamed `useSendAndConfirmTransaction` to `useSendAndConfirmTransactionCore`. - Updated exports to reflect the renaming. - Added `payModal` configuration to `useSendAndConfirmTransaction`. - Updated `CreateDirectListingButton`, `ClaimButton`, and `BuyDirectListingButton` to utilize the new `payModal` configuration. - Enhanced documentation for `useSendAndConfirmTransaction` with usage examples for the `Pay Modal`. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Pay Modal integrated into send-and-confirm transaction flows, matching send-only behavior. * Prebuilt buttons (Buy Direct Listing, Claim, Create Direct Listing) pass Pay Modal config and auto-fill metadata with sensible fallbacks for smoother top-ups. * Pay Modal options are configurable and compatible with gasless workflows. * **Documentation** * Added examples and guidance for configuring the Pay Modal (theme, disabling, and usage). <!-- end of auto-generated comment: release notes by coderabbit.ai -->
ec2ece0
to
597431e
Compare
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 (8)
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx (6)
91-91
: Guard against boolean/null before accessing metadata.
AccessingpayModal.metadata
whenpayModal
istrue
(boolean) ornull
will break typing or throw at runtime.Apply:
- const defaultPayModalMetadata = payModal ? payModal.metadata : undefined; + const defaultPayModalMetadata = + payModal && typeof payModal === "object" ? payModal.metadata : undefined;
99-105
: Don’t fetch Pay metadata when the modal is disabled.
Avoid unnecessary network call ifpayModal === false
.const { data: payMetadata } = useReadContract(getPayMetadata, { contract, listingId, queryOptions: { - enabled: !defaultPayModalMetadata, + enabled: payModal !== false && !defaultPayModalMetadata, }, });
146-159
: Fix ERC1155 quantity overwrite and lower-bound check.
_quantity
is always reset tolisting.quantity
; andquantity < 0n
allows0n
.- } else if (listing.asset.type === "ERC1155") { - if (typeof quantity === "bigint") { - if (quantity > listing.quantity) { - throw new Error( - `quantity exceeds available amount. Available: ${listing.quantity.toString()}`, - ); - } - if (quantity < 0n) { - throw new Error("Invalid quantity. Should be at least 1n"); - } - _quantity = quantity; - } - _quantity = listing.quantity; - } + } else if (listing.asset.type === "ERC1155") { + if (typeof quantity === "bigint") { + if (quantity > listing.quantity) { + throw new Error( + `quantity exceeds available amount. Available: ${listing.quantity.toString()}`, + ); + } + if (quantity < 1n) { + throw new Error("Invalid quantity. Should be at least 1n"); + } + _quantity = quantity; + } else { + _quantity = listing.quantity; + } + }
181-186
: Passing an object here re-enables the modal whenpayModal === false
.
This always passes a truthy object toTransactionButton
, defeating the opt-out.- <TransactionButton - payModal={{ - metadata: defaultPayModalMetadata || payMetadata, - ...payModal, - }} + <TransactionButton + payModal={ + payModal === false + ? false + : payModal && typeof payModal === "object" + ? { metadata: defaultPayModalMetadata || payMetadata, ...payModal } + : undefined + }
25-27
: Doc fix: wrong contract reference.
This component targets Marketplace v3, not Drop.- * The chain which the Drop contract is deployed on + * The chain which the Marketplace v3 contract is deployed on
51-80
: Add required custom TSDoc tag for public symbol.
Repo guideline requires a custom tag (e.g.,@beta
). Add one to this component’s TSDoc./** * This button is used with thirdweb Marketplace v3 contract, for buying NFT(s) from a listing. @@ * @transaction + * @beta */
packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts (2)
8-17
: Doc header references wrong hook.
Should referenceuseSendAndConfirmTransaction(Core)
notuseSendTransaction
.-/** - * Configuration for the `useSendTransaction` hook. - */ +/** + * Configuration for the `useSendAndConfirmTransactionCore` hook. + */
20-55
: Mark core hook as internal or fix examples.
This file exportsuseSendAndConfirmTransactionCore
but examples importuseSendAndConfirmTransaction
. Either mark this as internal to avoid duplicate public docs, or update examples accordingly./** * A hook to send a transaction. * @returns A mutation object to send a transaction. @@ - * import { useSendAndConfirmTransaction } from "thirdweb/react"; + * @internal + * Prefer `useSendAndConfirmTransaction` from `thirdweb/react` (web) or `thirdweb/react.native` (native). + * The examples below use the public re-exported name. + * + * import { useSendAndConfirmTransaction } from "thirdweb/react";
♻️ Duplicate comments (1)
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx (1)
107-115
: Preserve explicitfalse
and avoid null-object crash in hook config.
Current check treatsnull
as object and spreads it; also less explicit than needed.- const { mutateAsync } = useSendAndConfirmTransaction({ - payModal: - typeof payModal === "object" - ? { - ...payModal, - metadata: payModal.metadata || payMetadata, - } - : payModal, - }); + const { mutateAsync } = useSendAndConfirmTransaction({ + payModal: + payModal === false + ? false + : payModal && typeof payModal === "object" + ? { ...payModal, metadata: payModal.metadata || payMetadata } + : undefined, + });
🧹 Nitpick comments (1)
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx (1)
46-46
: Nit: double space.- * The component will also throw an error if you pass a `quantity` and it's greater than the listing's quantity + * The component will also throw an error if you pass a `quantity` and it's greater than the listing's quantity
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (9)
.changeset/pretty-geese-win.md
(1 hunks)packages/thirdweb/src/exports/react.native.ts
(1 hunks)packages/thirdweb/src/exports/react.ts
(1 hunks)packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts
(1 hunks)packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx
(1 hunks)packages/thirdweb/src/react/web/hooks/transaction/useSendTransaction.tsx
(1 hunks)packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx
(2 hunks)packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/index.tsx
(2 hunks)packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- .changeset/pretty-geese-win.md
- packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx
- packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/ClaimButton/index.tsx
- packages/thirdweb/src/exports/react.ts
- packages/thirdweb/src/react/web/hooks/transaction/useSendTransaction.tsx
- packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.tsx
- packages/thirdweb/src/exports/react.native.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}
: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/types
or localtypes.ts
barrels
Prefer type aliases over interface except for nominal shapes
Avoidany
andunknown
unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial
,Pick
, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}
: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/types
where applicable
Prefertype
aliases overinterface
except for nominal shapes
Avoidany
andunknown
unless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx
packages/thirdweb/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/thirdweb/**/*.{ts,tsx}
: Every public symbol must have comprehensive TSDoc with at least one compiling@example
and a custom tag (@beta
,@internal
,@experimental
, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g.,const { jsPDF } = await import("jspdf")
)
Files:
packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx
🧬 Code graph analysis (2)
packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts (1)
packages/thirdweb/src/exports/react.native.ts (1)
useSendAndConfirmTransactionCore
(62-62)
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx (2)
packages/thirdweb/src/exports/react.ts (1)
useSendAndConfirmTransaction
(127-127)packages/thirdweb/src/react/web/hooks/transaction/useSendAndConfirmTransaction.tsx (1)
useSendAndConfirmTransaction
(89-104)
⏰ 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). (8)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Unit Tests
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Build Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
packages/thirdweb/src/react/web/ui/prebuilt/thirdweb/BuyDirectListingButton/index.tsx (1)
12-12
: Import path change looks good.packages/thirdweb/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts (1)
57-78
: Core logic LGTM.
Error on missing account and delegation tosendAndConfirmTransaction
look correct.
PR-Codex overview
This PR focuses on integrating a Pay Modal into the
useSendAndConfirmTransaction
hook, similar to the existinguseSendTransaction
hook. It enhances user experience by allowing users to buy required funds if their wallet lacks sufficient balance.Detailed summary
useSendAndConfirmTransaction
touseSendAndConfirmTransactionCore
.useSendAndConfirmTransaction
.CreateDirectListingButton
,ClaimButton
, andBuyDirectListingButton
to use the new Pay Modal feature.useSendAndConfirmTransaction
from the appropriate module.Summary by CodeRabbit
New Features
Documentation