Skip to content

Conversation

@mikeredmond
Copy link
Member

@mikeredmond mikeredmond commented Dec 5, 2025

Description

This pull request introduces support for dApp-sponsored (delegated fee) transactions in the transaction hooks and UI, and improves the GitHub Actions workflows for preview environment deployment and teardown. The main changes add an optional dAppSponsoredUrl parameter throughout the transaction building and sending flow, and update the preview deployment workflow to enforce branch naming conventions for external pull requests.

dApp-Sponsored Transaction Support:

  • Added an optional dAppSponsoredUrl parameter to useBuildTransaction, useSendTransaction, and the PrivyWalletProviderContextType, allowing transactions to be sent via a delegator for sponsored fees. This includes updates to type definitions, function signatures, and transaction sending logic.

  • Updated the TransactionExamples component to demonstrate and handle dApp-sponsored transactions, including new button logic, modal state handling, and user feedback.

Preview Environment Workflow Improvements:

  • Enforced branch naming convention for external pull requests in the deploy-preview.yaml workflow, requiring branches to be prefixed with the GitHub username (e.g., username/feature-branch). The workflow now fails early if this is not met, and user-facing messages were updated accordingly.

  • Improved deployment comment logic in the preview deployment workflow to avoid duplicate comments by checking for an existing deployment comment before posting a new one.

  • Changed the destroy preview environment workflow trigger from pull_request to pull_request_target for better permission handling, and improved the logic for finding and removing deployment comments.

Demo

Screen.Recording.2025-12-02.at.11.27.33.mov

Closes #471

Summary by CodeRabbit

  • New Features

    • DApp‑sponsored transactions: optional delegator URL enables sponsored transaction flow, UI changes for sponsored flow, retry path, and updated status/receipt handling.
  • Chores

    • CI/CD preview improvements: branch-name validation for external PRs (username/branch), normalized preview URLs, and reliable preview comment handling (find/create/replace/delete) for accurate deployment comments.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 5, 2025

Walkthrough

Adds optional dApp-sponsored transaction support by introducing dAppSponsoredUrl across build/send hooks and the Privy wallet provider, wires an optional sponsored flow into example UI, and updates GitHub workflows to validate branch prefixes, normalize branch names, find/update preview comments, and consolidate comment removal.

Changes

Cohort / File(s) Summary
GitHub workflows
​.github/workflows/deploy-preview.yaml, ​.github/workflows/destroy-preview-env.yaml
Add branch-name prefix validation for external PRs; add a "Find Comment" step and pass found comment-id to deployment comment creation to enable update/replace; normalize/sanitize branch name for preview URLs; change destroy-preview trigger to pull_request_target and remove duplicated comment-deletion steps.
Build-layer transaction hook
packages/vechain-kit/src/hooks/thor/transactions/useBuildTransaction.ts
Add dAppSponsoredUrl?: string to BuildTransactionProps and useBuildTransaction params; thread dAppSponsoredUrl into useSendTransaction invocation and dependency arrays; forward through adapter/send paths.
Send-layer transaction hook
packages/vechain-kit/src/hooks/thor/transactions/useSendTransaction.ts
Add dAppSponsoredUrl?: string to UseSendTransactionProps and public hook signature; expand sendTransaction to accept (clauses?, dAppSponsoredUrl?, privyUIOptions?); include dAppSponsoredUrl in Privy payloads, adapter signatures, internal calls, and memoization dependencies.
Wallet provider integration
packages/vechain-kit/src/providers/PrivyWalletProvider.tsx
Expose dAppSponsoredUrl?: string on provider props/context and send payload; bypass generic delegator when dAppSponsoredUrl present; forward dAppSponsoredUrl into signAndSend and gas-payer selection.
Example UI
examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx
Add parallel buildTransactionWithDAppSponsored flow and retry handler; prefer sponsored flow where available; propagate sponsored status/receipt/errors to modal and button states; update modal copy and add delegator URL placeholder.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as TransactionExamples
    participant Build as useBuildTransaction
    participant Send as useSendTransaction
    participant Provider as PrivyWalletProvider
    participant Delegator as GasPayerService
    participant Privy as Privy Service

    User->>UI: trigger transaction
    UI->>Build: buildTransactionWithDAppSponsored(dAppSponsoredUrl?)
    Build->>Send: prepare send config (includes dAppSponsoredUrl)
    UI->>Send: sendTransaction(clauses, dAppSponsoredUrl, privyUIOptions?)
    Send->>Provider: sendTransaction(payload includes dAppSponsoredUrl)
    Provider->>Provider: evaluate dAppSponsoredUrl
    alt dAppSponsoredUrl provided
        Provider->>Delegator: use provided dAppSponsoredUrl as gas-payer endpoint
    else
        Provider->>Delegator: use generic delegator endpoint
    end
    Delegator->>Privy: sign & submit (sponsor fees)
    Privy->>Provider: tx result
    Provider->>UI: return tx result (status/receipt/error)
    UI->>User: display result / allow retry
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Review public API/signature changes in useSendTransaction.ts (new sendTransaction parameters) and update all call sites.
  • Verify dAppSponsoredUrl propagation and dependency arrays (useCallback/useMemo) to avoid stale closures.
  • Inspect PrivyWalletProvider.tsx delegator selection, fallback logic, and error handling for delegator endpoints.
  • Validate example UI state handling in TransactionExamples.tsx for sponsored vs non-sponsored flows.
  • Confirm GitHub workflow branch-processing, comment-finding/updating logic, and correct use of pull_request_target.

Poem

🐰 I found a tiny sponsor stream,
stitched it into hooks and dream.
Provider hops, delegator sings,
fees shrink small on gentle springs.
Hooray — sponsored steps for new users gleam!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately and concisely summarizes the main feature: allowing one-off sponsored transactions as an optional parameter in transaction hooks.
Description check ✅ Passed The PR description comprehensively covers all major changes, includes required sections (Description, Closes #471), and clearly explains both the dApp-sponsored transaction support and workflow improvements.
Linked Issues check ✅ Passed The PR successfully implements all requirements from #471: adds optional dAppSponsoredUrl parameter to transaction hooks, handles two-step signing delegation internally, and enables one-off transaction sponsorship for UX scenarios like gasless onboarding.
Out of Scope Changes check ✅ Passed The PR includes legitimate scope expansions: GitHub Actions workflow improvements (branch naming validation, comment deduplication) are necessary infrastructure updates supporting the sponsored transaction feature and deployment of the changes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mike/sponsor-specific-txs

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 5, 2025

🚀 Preview environment deployed!

Preview URL: https://preview.vechainkit.vechain.org/mikesponsor-specific-txs

@github-actions
Copy link

github-actions bot commented Dec 5, 2025

Size Change: +3.89 kB (+0.07%)

Total Size: 5.39 MB

Filename Size Change
packages/vechain-kit/dist/index-BD-k_dLp.d.cts 0 B -144 kB (removed) 🏆
packages/vechain-kit/dist/index-BD-k_dLp.d.cts.map 0 B -41.1 kB (removed) 🏆
packages/vechain-kit/dist/index-BN8V0jxo.d.mts 0 B -5.63 kB (removed) 🏆
packages/vechain-kit/dist/index-BN8V0jxo.d.mts.map 0 B -2.99 kB (removed) 🏆
packages/vechain-kit/dist/index-CRQ3_5RL.d.mts 0 B -144 kB (removed) 🏆
packages/vechain-kit/dist/index-CRQ3_5RL.d.mts.map 0 B -41.1 kB (removed) 🏆
packages/vechain-kit/dist/index-DSMUkHcK.d.cts 0 B -5.63 kB (removed) 🏆
packages/vechain-kit/dist/index-DSMUkHcK.d.cts.map 0 B -2.99 kB (removed) 🏆
packages/vechain-kit/dist/index.cjs.map 1.73 MB +1.19 kB (+0.07%)
packages/vechain-kit/dist/index.mjs.map 1.68 MB +1.19 kB (+0.07%)
packages/vechain-kit/dist/index-CG2_DiSi.d.mts 145 kB +145 kB (new file) 🆕
packages/vechain-kit/dist/index-CG2_DiSi.d.mts.map 41.3 kB +41.3 kB (new file) 🆕
packages/vechain-kit/dist/index-ClfDxOL0.d.cts 144 kB +144 kB (new file) 🆕
packages/vechain-kit/dist/index-ClfDxOL0.d.cts.map 41.3 kB +41.3 kB (new file) 🆕
packages/vechain-kit/dist/index-CWViOs1U.d.mts 5.63 kB +5.63 kB (new file) 🆕
packages/vechain-kit/dist/index-CWViOs1U.d.mts.map 2.99 kB +2.99 kB (new file) 🆕
packages/vechain-kit/dist/index-u3CPquCV.d.cts 5.63 kB +5.63 kB (new file) 🆕
packages/vechain-kit/dist/index-u3CPquCV.d.cts.map 2.99 kB +2.99 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size Change
packages/vechain-kit/dist/assets 4.1 kB 0 B
packages/vechain-kit/dist/assets-aAdDxPJu.mjs 50.1 kB 0 B
packages/vechain-kit/dist/assets-aAdDxPJu.mjs.map 70.2 kB 0 B
packages/vechain-kit/dist/assets-DXVXPy3w.cjs 54.8 kB 0 B
packages/vechain-kit/dist/assets-DXVXPy3w.cjs.map 71.6 kB 0 B
packages/vechain-kit/dist/assets/index.cjs 716 B 0 B
packages/vechain-kit/dist/assets/index.d.cts 973 B 0 B
packages/vechain-kit/dist/assets/index.d.mts 973 B 0 B
packages/vechain-kit/dist/assets/index.mjs 718 B 0 B
packages/vechain-kit/dist/index.cjs 571 kB +124 B (+0.02%)
packages/vechain-kit/dist/index.d.cts 20.1 kB 0 B
packages/vechain-kit/dist/index.d.mts 20.1 kB 0 B
packages/vechain-kit/dist/index.mjs 537 kB +125 B (+0.02%)
packages/vechain-kit/dist/utils 4.1 kB 0 B
packages/vechain-kit/dist/utils-Bl-JeVTg.cjs 26.2 kB 0 B
packages/vechain-kit/dist/utils-Bl-JeVTg.cjs.map 63 kB 0 B
packages/vechain-kit/dist/utils-DAs6kMGs.mjs 21.1 kB 0 B
packages/vechain-kit/dist/utils-DAs6kMGs.mjs.map 62.7 kB 0 B
packages/vechain-kit/dist/utils/index.cjs 1.91 kB 0 B
packages/vechain-kit/dist/utils/index.d.cts 2.94 kB 0 B
packages/vechain-kit/dist/utils/index.d.mts 2.94 kB 0 B
packages/vechain-kit/dist/utils/index.mjs 1.93 kB 0 B

compressed-size-action

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
.github/workflows/deploy-preview.yaml (1)

128-137: Condition prevents comment updates; comment will never be edited after initial creation.

The conditional if: steps.find-comment.outputs.comment-id == '' causes the step to run only when no existing comment is found. This means existing comments are never updated, defeating the purpose of the Find Comment step.

Remove the condition or always run the step so that create-or-update-comment can update existing deployment comments. The action handles both scenarios: if comment-id is provided, it updates; if empty, it creates.

  - name: Create Deployment Comment
    uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
-   if: steps.find-comment.outputs.comment-id == ''
    with:
        comment-id: ${{ steps.find-comment.outputs.comment-id }}
packages/vechain-kit/src/hooks/thor/transactions/useSendTransaction.ts (1)

168-189: dAppSponsoredUrl parameter is accepted but unused in the VeChain wallet (non-Privy) code path.

The parameter is passed to sendTransaction (line 132) but only used when connected via Privy (line 145). In the VeChain wallet path (lines 168-188), the parameter is ignored and buildTransactionBody is called with only an isDelegated flag, which doesn't support per-transaction sponsored URLs. The TODO comment at line 172 ("kit-migration check how to pass the delegator url") confirms this is incomplete. Either this feature needs to be implemented for VeChain wallets, or the parameter should be removed from the non-Privy code path to avoid confusion about its availability.

packages/vechain-kit/src/hooks/thor/transactions/useBuildTransaction.ts (1)

62-79: Remove unnecessary dAppSponsoredUrl parameter from useSendTransaction hook props.

The dAppSponsoredUrl parameter destructured at the hook level (line 112 of useSendTransaction.ts) is never used—it appears only in the dependency array but not in any actual logic. The sendTransactionAdapter function accepts and uses dAppSponsoredUrl as a call-time parameter instead. In useBuildTransaction, passing dAppSponsoredUrl to useSendTransaction at line 68 is unnecessary; only the call-time pass at line 77 has effect. Remove the hook-level parameter to eliminate dead code and the apparent redundancy.

🧹 Nitpick comments (1)
examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx (1)

48-66: Demo placeholder for dAppSponsoredUrl is commented out.

The dAppSponsoredUrl is commented out, which means this demo doesn't actually exercise the sponsored transaction flow. Consider either:

  1. Adding a placeholder URL that developers can see in action, or
  2. Adding a comment explaining how to test with a real delegator URL.
         suggestedMaxGas: undefined,
-        // dAppSponsoredUrl: "", <--- YOUR DELEGATOR URL HERE
+        // To test sponsored transactions, uncomment and provide your delegator URL:
+        // dAppSponsoredUrl: "https://sponsor.example.com/delegate",
     });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deac832 and c73ed0c.

📒 Files selected for processing (6)
  • .github/workflows/deploy-preview.yaml (4 hunks)
  • .github/workflows/destroy-preview-env.yaml (2 hunks)
  • examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx (4 hunks)
  • packages/vechain-kit/src/hooks/thor/transactions/useBuildTransaction.ts (5 hunks)
  • packages/vechain-kit/src/hooks/thor/transactions/useSendTransaction.ts (10 hunks)
  • packages/vechain-kit/src/providers/PrivyWalletProvider.tsx (6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/migration-guide-to-v2.mdc)

**/*.{ts,tsx}: In VeChain Kit Version 2, use useThor instead of useConnex for contract interactions
For single contract read operations, use the useCallClause hook with the pattern: import dependencies, define ABI and method as const, create query key function using getCallClauseQueryKeyWithArgs, and wrap with useCallClause including data transformation in the select option
For multiple parallel contract calls, use the executeMultipleClausesCall utility wrapped in a useQuery hook with the pattern: define query key function, use executeMultipleClausesCall in queryFn mapping items to clause objects, and transform results
For transaction building and sending, use the useBuildTransaction hook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action
Always provide an arguments array for contract calls, even when no parameters are required - use an empty array for parameter-less functions to enable TypeScript type checking
Always conditionally enable queries using the enabled property to prevent unnecessary contract calls, checking for all required parameters: enabled: !!requiredParam && !!otherRequiredParam
Use the select option in useCallClause or transform data in queryFn to handle data transformation, particularly for converting BigInt values to strings and normalizing contract return data
Maintain consistent query key patterns: use getCallClauseQueryKeyWithArgs for contract calls with arguments and getCallClauseQueryKey for calls without arguments to ensure proper caching and invalidation
Use TypeScript as const assertions for method names and as 0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions

Files:

  • packages/vechain-kit/src/hooks/thor/transactions/useBuildTransaction.ts
  • examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx
  • packages/vechain-kit/src/providers/PrivyWalletProvider.tsx
  • packages/vechain-kit/src/hooks/thor/transactions/useSendTransaction.ts
🧠 Learnings (3)
📚 Learning: 2025-12-01T13:01:33.771Z
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : For transaction building and sending, use the `useBuildTransaction` hook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action

Applied to files:

  • packages/vechain-kit/src/hooks/thor/transactions/useBuildTransaction.ts
  • examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx
  • packages/vechain-kit/src/providers/PrivyWalletProvider.tsx
  • packages/vechain-kit/src/hooks/thor/transactions/useSendTransaction.ts
📚 Learning: 2025-12-01T13:01:33.771Z
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : In VeChain Kit Version 2, use `useThor` instead of `useConnex` for contract interactions

Applied to files:

  • packages/vechain-kit/src/hooks/thor/transactions/useBuildTransaction.ts
  • packages/vechain-kit/src/hooks/thor/transactions/useSendTransaction.ts
📚 Learning: 2025-12-01T13:01:33.771Z
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : For multiple parallel contract calls, use the `executeMultipleClausesCall` utility wrapped in a `useQuery` hook with the pattern: define query key function, use `executeMultipleClausesCall` in queryFn mapping items to clause objects, and transform results

Applied to files:

  • packages/vechain-kit/src/hooks/thor/transactions/useBuildTransaction.ts
  • packages/vechain-kit/src/hooks/thor/transactions/useSendTransaction.ts
🧬 Code graph analysis (1)
examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx (2)
packages/vechain-kit/src/hooks/thor/transactions/useBuildTransaction.ts (1)
  • useBuildTransaction (30-83)
examples/next-template/src/app/constants.ts (1)
  • b3trMainnetAddress (1-1)
🪛 Biome (2.1.2)
examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx

[error] 95-95: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

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)

⏰ 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). (4)
  • GitHub Check: Lint & Build
  • GitHub Check: e2e-test
  • GitHub Check: build-size-check
  • GitHub Check: deploy
🔇 Additional comments (6)
.github/workflows/destroy-preview-env.yaml (2)

4-4: Clarify the security implications of pull_request_target trigger.

The switch from pull_request to pull_request_target changes workflow execution to the base branch context (main) with full access to secrets. While this provides better permission isolation for untrusted external PRs, it should be explicitly documented in your PR or ADR to ensure the team understands the security posture change and its implications.

Is this change intended for security hardening? If so, please confirm it's aligned with your organization's GitHub Actions security guidelines.


45-51: LGTM: Appropriate scope reduction for BRANCH_NAME.

Moving BRANCH_NAME from top-level env to step-level env (line 48) is good practice—it limits variable visibility to where it's used and reduces potential for accidental reuse in unintended contexts.

packages/vechain-kit/src/providers/PrivyWalletProvider.tsx (2)

189-195: Logic correctly bypasses generic delegator when dAppSponsoredUrl is provided.

The condition genericDelegator && !dAppSponsoredUrl ensures that when a per-transaction sponsor URL is provided, it takes precedence over the generic delegator path. This aligns with the PR objective of allowing one-off sponsored transactions.


104-125: LGTM: signAndSend correctly prioritizes dAppSponsoredUrl.

The dAppSponsoredUrl ?? delegatorUrl fallback ensures the per-transaction sponsor URL takes precedence, falling back to the default delegator URL when not provided. This is the correct behavior for enabling one-off sponsored transactions.

packages/vechain-kit/src/hooks/thor/transactions/useSendTransaction.ts (2)

214-241: Adapter signature updated correctly to forward dAppSponsoredUrl.

The sendTransactionAdapter now accepts _dAppSponsoredUrl as a second parameter and forwards it to the internal sendTransaction. This enables callers to specify a per-transaction sponsor URL.


52-60: Public API correctly updated for dAppSponsoredUrl parameter.

The UseSendTransactionReturnValue.sendTransaction signature now includes dAppSponsoredUrl as an optional second parameter, aligning with the implementation and enabling consumers to pass the sponsor URL per transaction.

Copy link

@coderabbitai coderabbitai bot left a 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 (3)
examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx (3)

48-66: Consider extracting the shared clause builder to reduce duplication.

The buildTransactionWithDAppSponsored hook duplicates the entire configuration from the first useBuildTransaction hook (lines 22-46), differing only in the commented-out dAppSponsoredUrl. While this duplication may aid clarity in a demo, extracting the common clauseBuilder function would demonstrate best practices and improve maintainability.

Apply this diff to extract the shared logic:

+    const buildDummyTransferClause = useCallback(() => {
+        if (!account?.address) return [];
+
+        return [
+            {
+                ...thor.contracts
+                    .load(b3trMainnetAddress, IB3TR__factory.abi)
+                    .clause.transfer(account.address, BigInt('0')).clause,
+                comment: `This is a dummy transaction to test the transaction modal. Confirm to transfer 0 B3TR to ${account?.address}`,
+            },
+        ];
+    }, [account?.address, thor.contracts]);
+
     const {
         sendTransaction,
         status,
         txReceipt,
         isTransactionPending,
         error,
         resetStatus,
     } = useBuildTransaction({
-        clauseBuilder: () => {
-            if (!account?.address) return [];
-
-            return [
-                {
-                    ...thor.contracts
-                        .load(b3trMainnetAddress, IB3TR__factory.abi)
-                        .clause.transfer(account.address, BigInt('0')).clause,
-                    comment: `This is a dummy transaction to test the transaction modal. Confirm to transfer 0 B3TR to ${account?.address}`,
-                },
-            ];
-        },
+        clauseBuilder: buildDummyTransferClause,
         refetchQueryKeys: [],
         onSuccess: () => {},
         onFailure: () => {},
         suggestedMaxGas: undefined,
     });

     const buildTransactionWithDAppSponsored = useBuildTransaction({
-        clauseBuilder: () => {
-            if (!account?.address) return [];
-
-            return [
-                {
-                    ...thor.contracts
-                        .load(b3trMainnetAddress, IB3TR__factory.abi)
-                        .clause.transfer(account.address, BigInt('0')).clause,
-                    comment: `This is a dummy transaction to test the transaction modal. Confirm to transfer 0 B3TR to ${account?.address}`,
-                },
-            ];
-        },
+        clauseBuilder: buildDummyTransferClause,
         refetchQueryKeys: [],
         onSuccess: () => {},
         onFailure: () => {},
         suggestedMaxGas: undefined,
         // dAppSponsoredUrl: "", <--- YOUR DELEGATOR URL HERE
     });

117-118: Optional: Simplify the fallback logic.

Since buildTransactionWithDAppSponsored is always returned by useBuildTransaction, its isTransactionPending property should always be defined (true or false), making the nullish coalescing fallback unnecessary. However, this defensive pattern is reasonable for a demo and doesn't cause any functional issues.

If you prefer to simplify:

-                        isLoading={buildTransactionWithDAppSponsored.isTransactionPending ?? isTransactionPending}
-                        isDisabled={buildTransactionWithDAppSponsored.isTransactionPending ?? isTransactionPending}
+                        isLoading={buildTransactionWithDAppSponsored.isTransactionPending}
+                        isDisabled={buildTransactionWithDAppSponsored.isTransactionPending}

141-144: Optional: Consider simplifying modal prop fallbacks.

Similar to the button states, the nullish coalescing fallbacks for status, txReceipt, error, and onTryAgain are likely unnecessary since buildTransactionWithDAppSponsored is always defined. However, this pattern is acceptable for demonstrating both transaction flows in an example.

If you prefer to use only the sponsored flow:

-                status={buildTransactionWithDAppSponsored.status ?? status}
-                txReceipt={buildTransactionWithDAppSponsored.txReceipt ?? txReceipt}
-                txError={buildTransactionWithDAppSponsored.error ?? error}
-                onTryAgain={handleTryAgainWithSponsoredModal ?? handleTryAgain}
+                status={buildTransactionWithDAppSponsored.status}
+                txReceipt={buildTransactionWithDAppSponsored.txReceipt}
+                txError={buildTransactionWithDAppSponsored.error}
+                onTryAgain={handleTryAgainWithSponsoredModal}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 158d622 and d4163d8.

📒 Files selected for processing (1)
  • examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/migration-guide-to-v2.mdc)

**/*.{ts,tsx}: In VeChain Kit Version 2, use useThor instead of useConnex for contract interactions
For single contract read operations, use the useCallClause hook with the pattern: import dependencies, define ABI and method as const, create query key function using getCallClauseQueryKeyWithArgs, and wrap with useCallClause including data transformation in the select option
For multiple parallel contract calls, use the executeMultipleClausesCall utility wrapped in a useQuery hook with the pattern: define query key function, use executeMultipleClausesCall in queryFn mapping items to clause objects, and transform results
For transaction building and sending, use the useBuildTransaction hook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action
Always provide an arguments array for contract calls, even when no parameters are required - use an empty array for parameter-less functions to enable TypeScript type checking
Always conditionally enable queries using the enabled property to prevent unnecessary contract calls, checking for all required parameters: enabled: !!requiredParam && !!otherRequiredParam
Use the select option in useCallClause or transform data in queryFn to handle data transformation, particularly for converting BigInt values to strings and normalizing contract return data
Maintain consistent query key patterns: use getCallClauseQueryKeyWithArgs for contract calls with arguments and getCallClauseQueryKey for calls without arguments to ensure proper caching and invalidation
Use TypeScript as const assertions for method names and as 0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions

Files:

  • examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : For transaction building and sending, use the `useBuildTransaction` hook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action
📚 Learning: 2025-12-01T13:01:33.771Z
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : For transaction building and sending, use the `useBuildTransaction` hook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action

Applied to files:

  • examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx
📚 Learning: 2025-12-01T13:01:33.771Z
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : Always conditionally enable queries using the `enabled` property to prevent unnecessary contract calls, checking for all required parameters: `enabled: !!requiredParam && !!otherRequiredParam`

Applied to files:

  • examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx
🧬 Code graph analysis (1)
examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx (2)
packages/vechain-kit/src/hooks/thor/transactions/useBuildTransaction.ts (1)
  • useBuildTransaction (30-83)
examples/next-template/src/app/constants.ts (1)
  • b3trMainnetAddress (1-1)
⏰ 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)
  • GitHub Check: build-size-check
🔇 Additional comments (3)
examples/next-template/src/app/components/features/TransactionExamples/TransactionExamples.tsx (3)

85-88: Good fix for the Promise fallback logic.

The previous incorrect use of nullish coalescing with Promises has been properly resolved. The modal now directly invokes the sponsored transaction flow, which correctly demonstrates the feature.


95-98: Excellent fix for the Rules of Hooks violation.

The conditional hook call has been properly resolved. useCallback is now invoked unconditionally, which complies with React's Rules of Hooks. The retry logic correctly resets and re-sends the sponsored transaction.


146-146: Clear and appropriate title update.

The modal title correctly indicates this demonstrates a DApp-sponsored transaction, helping developers understand which flow they're testing.

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.

💡 [REQUEST] - Add native support for Fee Delegation in the transaction hooks

3 participants