Feat/gasless transactions - #89
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR adds optional EIP-7702/paymaster execution for title-escrow actions, integrates gasless verification and pay-on-behalf UI, adds supporting dependencies and tests, and updates E2E fixtures, filtering, setup, and assertions. ChangesGasless transaction and application UI changes
E2E workflow and fixture updates
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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 |
permissionless@0.3.7 declares peerOptional ox@^0.11.3 but viem@2.55.1 ships ox@0.14.30, which is out of range. trustvc@2.15.0-beta.2 requires both viem@^2.53.1 and permissionless@^0.3.6, so neither can be downgraded. legacy-peer-deps makes npm skip the conflicting optional peer check. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/index.css (1)
3873-3886: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
gap: 10pxsilently overrides the existingrow-gap: 0px.Adding
gap: 10pxafterrow-gap: 0pxin.dropdown-btn-framechanges the effective row-gap from0pxto10px(the shorthandgapoverwrites the longhand set immediately above it), flagged by stylelint'sdeclaration-block-no-shorthand-property-overrides. If the intent was to add column spacing only, usecolumn-gap: 10pxinstead ofgap.🎯 Proposed fix
padding: 0px; - row-gap: 0px; - gap: 10px; + column-gap: 10px; + row-gap: 0px;🤖 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 `@src/index.css` around lines 3873 - 3886, Update the .dropdown-btn-frame spacing declarations to use column-gap: 10px instead of the gap shorthand, preserving the existing row-gap: 0px behavior.Source: Linters/SAST tools
🧹 Nitpick comments (4)
src/index.css (1)
2226-2373: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFixed pixel widths in the new gasless error/success blocks have no responsive fallback.
.gasless-error-text(width: 355px),.pay-on-behalf-note(width: 546px),.pay-on-behalf-note-frame(width: 315px), and.pay-on-behalf-note-text(width: 278px) use hard-coded widths with no@mediaadjustment, unlike sibling blocks in this same section (.vr-card-header,.vr-upload-btn) which already handle themax-width: 712pxbreakpoint. On narrow viewports this text/frame combination is likely to overflow or get clipped.🤖 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 `@src/index.css` around lines 2226 - 2373, Replace the fixed widths in .gasless-error-text, .pay-on-behalf-note, .pay-on-behalf-note-frame, and .pay-on-behalf-note-text with responsive sizing, adding the established max-width: 712px breakpoint behavior used by nearby .vr-card-header and .vr-upload-btn styles. Ensure the gasless error and pay-on-behalf content shrink within narrow containers without overflow or clipping.package.json (1)
36-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMove
@testing-library/domintodevDependencies.
@testing-library/domis only pulled into production installs throughdependencies;devDependenciesalready pins the test framework packages, including@testing-library/react, and there are no non-test imports underdependencies.🤖 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 `@package.json` around lines 36 - 38, Move `@testing-library/dom` from dependencies to devDependencies in package.json, keeping its existing version unchanged and grouped with the other testing packages.src/gasless/useGaslessNominate.ts (1)
48-140: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftExtract the shared gasless-eligibility + client-build logic.
This
sendbody (paymaster resolution,hasGaslessConfiggate, delegation + whitelist checks,buildSmartAccountClientcall, error mapping, state transitions) is duplicated almost verbatim across alluseGasless*hooks (useGaslessTransferBeneficiary,useGaslessRejectTransferHolder,useGaslessRejectTransferOwners,useGaslessReturnToIssuer,useGaslessRejectReturned, etc.). Consider a shared helper/factory that takes the gasless/non-gasless callables so each hook only supplies its two trustvc functions. This removes ~9 copies and keeps the eligibility contract in one place.
getRpcUrl(chainId!)is also called twice per send here — reuse the earlierrpcUrl.🤖 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 `@src/gasless/useGaslessNominate.ts` around lines 48 - 140, Extract the duplicated gasless eligibility, paymaster resolution, smart-account client construction, error mapping, and state-transition flow from send into a shared helper or factory used by the useGasless* hooks, with each hook supplying only its gasless and non-gasless callables. Preserve the existing eligibility behavior and trustvc function parameters, and reuse the rpcUrl already resolved during eligibility instead of calling getRpcUrl(chainId!) again when building the client.src/gasless/useGaslessTransferHolder.ts (1)
40-158: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftConsider extracting the shared gasless scaffolding. This eligibility resolution + delegation/whitelist check + gasless-vs-fallback dispatch + state machine is duplicated near-verbatim across all 10
useGasless*hooks. A single parameterized helper (taking the gasless/regular callables and param shape) would remove ~120 duplicated lines per hook and keep the routing logic in one place.🤖 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 `@src/gasless/useGaslessTransferHolder.ts` around lines 40 - 158, Extract the shared gasless flow currently implemented in useGaslessTransferHolder.send—including eligibility resolution, EIP-7702 delegation and whitelist checks, gasless-versus-regular dispatch, and state/error transitions—into one parameterized reusable helper. Update useGaslessTransferHolder and the other useGasless* hooks to provide their operation-specific callables and parameters while preserving existing behavior and hook state APIs.
🤖 Prompt for all review comments with 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.
Inline comments:
In `@e2e/playwright.config.ts`:
- Line 11: Update the Playwright configuration around retries and the
transaction specs so failed CI retries do not reuse mutated Hardhat blockchain
state: either reset/redeploy the chain and wallet before each retry, or disable
retries for the stateful nomination, transfer, reject, and return tests while
preserving retries for unrelated specs.
In `@src/components/common/Tag/Tag.tsx`:
- Line 54: Update the className in the Tag component to replace the undefined
font-urbanist-bold utility with the supported font-urbanist and font-bold
utilities, preserving the other styling classes.
In `@src/components/home/VerifySection/VerifyResult.tsx`:
- Around line 159-161: The successful checkGasless branch in VerifyResult.tsx
must persist the trimmed paymaster value using the trustvc_paymaster_${account}
localStorage key; restore this write before setting gaslessStatus to success. In
ActionSelectionForm.tsx lines 193-203, verify the existing pay-on-behalf note
renders once that key is written; make no direct change there unless required by
the verification.
- Around line 82-93: Update the useEffect delegation check to ignore results
from stale requests when account or chainId changes. Track whether the effect is
still active, only call setIsDelegated for the current check, and clean up that
active state in the effect’s return function; preserve the existing early resets
for missing account or RPC URL.
In `@src/gasless/buildSmartAccountClient.ts`:
- Line 34: Update the Pimlico API key configuration used by
buildSmartAccountClient and VITE_PIMLICO_API_KEY so the key is restricted to the
intended application origin/domain before embedding it in the client-side RPC
URL; preserve the existing chain-specific Pimlico endpoint construction while
ensuring leaked keys cannot be reused from other domains.
In `@src/gasless/useGaslessRejectReturned.ts`:
- Around line 66-121: Update hasGaslessConfig in the gasless eligibility flow to
also require tokenRegistryAddress and tokenId before setting useGasless or
entering rejectReturnedGasless. Preserve the existing whitelist checks and
ensure the gasless branch cannot reach non-null assertions when either consumed
parameter is missing.
In `@src/gasless/useGaslessTransferHolder.ts`:
- Around line 70-74: Restore persistence for validated user-entered paymaster
addresses by re-enabling the localStorage.setItem call in VerifyResult.tsx after
trimming and validating the address, using the trustvc_paymaster_${account} key
consumed by the gasless hooks. The affected read sites require no direct
changes: src/gasless/useGaslessTransferHolder.ts lines 70-74,
src/gasless/useGaslessTransferOwners.ts lines 63-67, and
src/gasless/useGaslessRejectTransferBeneficiary.ts lines 64-67 already read the
stored value correctly.
In `@src/index.css`:
- Around line 15-29: Update the affected `@font-face` rules and selectors in
src/index.css to use unquoted font-family names, including Urbanist and Avenir,
consistent with the rest of the file. In .gasless-address-input-field, remove
the duplicate border-radius declaration. Remove extra blank lines before
declarations in the new check-gasless and pay-on-behalf rules so they satisfy
declaration-empty-line-before.
---
Outside diff comments:
In `@src/index.css`:
- Around line 3873-3886: Update the .dropdown-btn-frame spacing declarations to
use column-gap: 10px instead of the gap shorthand, preserving the existing
row-gap: 0px behavior.
---
Nitpick comments:
In `@package.json`:
- Around line 36-38: Move `@testing-library/dom` from dependencies to
devDependencies in package.json, keeping its existing version unchanged and
grouped with the other testing packages.
In `@src/gasless/useGaslessNominate.ts`:
- Around line 48-140: Extract the duplicated gasless eligibility, paymaster
resolution, smart-account client construction, error mapping, and
state-transition flow from send into a shared helper or factory used by the
useGasless* hooks, with each hook supplying only its gasless and non-gasless
callables. Preserve the existing eligibility behavior and trustvc function
parameters, and reuse the rpcUrl already resolved during eligibility instead of
calling getRpcUrl(chainId!) again when building the client.
In `@src/gasless/useGaslessTransferHolder.ts`:
- Around line 40-158: Extract the shared gasless flow currently implemented in
useGaslessTransferHolder.send—including eligibility resolution, EIP-7702
delegation and whitelist checks, gasless-versus-regular dispatch, and
state/error transitions—into one parameterized reusable helper. Update
useGaslessTransferHolder and the other useGasless* hooks to provide their
operation-specific callables and parameters while preserving existing behavior
and hook state APIs.
In `@src/index.css`:
- Around line 2226-2373: Replace the fixed widths in .gasless-error-text,
.pay-on-behalf-note, .pay-on-behalf-note-frame, and .pay-on-behalf-note-text
with responsive sizing, adding the established max-width: 712px breakpoint
behavior used by nearby .vr-card-header and .vr-upload-btn styles. Ensure the
gasless error and pay-on-behalf content shrink within narrow containers without
overflow or clipping.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: cbfc881d-8cfc-4af2-b925-4f667db255be
⛔ Files ignored due to path filters (11)
package-lock.jsonis excluded by!**/package-lock.jsonpublic/fonts/GilroyBold/font.woffis excluded by!**/*.woffpublic/fonts/GilroyBold/font.woff2is excluded by!**/*.woff2public/fonts/GilroyExtraBold/font.woffis excluded by!**/*.woffpublic/fonts/GilroyExtraBold/font.woff2is excluded by!**/*.woff2public/fonts/GilroyLight/font.woffis excluded by!**/*.woffpublic/fonts/GilroyLight/font.woff2is excluded by!**/*.woff2public/fonts/GilroyMedium/font.woffis excluded by!**/*.woffpublic/fonts/GilroyMedium/font.woff2is excluded by!**/*.woff2public/fonts/Urbanist/Urbanist-Italic-Variable.woff2is excluded by!**/*.woff2public/fonts/Urbanist/Urbanist-Variable.woff2is excluded by!**/*.woff2
📒 Files selected for processing (56)
.github/workflows/e2e.ymle2e/fixtures/local/w3c/tr_accept_surrender.jsone2e/fixtures/local/w3c/tr_reject_surrender.jsone2e/helpers/actions.tse2e/playwright.config.tse2e/setup-contracts.cjse2e/tests/nominate.spec.tse2e/tests/reject-return-to-issuer.spec.tse2e/tests/transfer-and-reject-beneficiary.spec.tse2e/tests/transfer-and-reject-owners.spec.tspackage.jsonpublic/fonts/Urbanist/OFL.txtsrc/components/AssetManagementPanel/AssetManagementForm/FormVariants/ActionSelectionForm/ActionSelectionForm.tsxsrc/components/about/CapabilityCard/CapabilityCard.tsxsrc/components/about/EcosystemCard/EcosystemCard.tsxsrc/components/common/AddressBookOverlay/AddressBookOverlay.tsxsrc/components/common/Button/Button.tsxsrc/components/common/FormAlert/FormAlert.tsxsrc/components/common/Icons/Icons.tsxsrc/components/common/Icons/index.tssrc/components/common/Navbar/Navbar.tsxsrc/components/common/PartnerCard/index.tsxsrc/components/common/Recaptcha/Recaptcha.tsxsrc/components/common/Tag/Tag.tsxsrc/components/common/TextAreaField/TextAreaField.tsxsrc/components/common/TextField/TextField.tsxsrc/components/common/contexts/TokenInformationContext/TokenInformationContext.tsxsrc/components/home/PartnersSection/index.tsxsrc/components/home/VerifySection/VerifyError.tsxsrc/components/home/VerifySection/VerifyResult.tsxsrc/gasless/buildSmartAccountClient.tssrc/gasless/checkDelegation.test.tssrc/gasless/checkDelegation.tssrc/gasless/checkPaymasterWhitelist.test.tssrc/gasless/checkPaymasterWhitelist.tssrc/gasless/gaslessHooks.test.tsxsrc/gasless/index.tssrc/gasless/useGaslessAcceptReturned.tssrc/gasless/useGaslessNominate.tssrc/gasless/useGaslessRejectReturned.tssrc/gasless/useGaslessRejectTransferBeneficiary.tssrc/gasless/useGaslessRejectTransferHolder.tssrc/gasless/useGaslessRejectTransferOwners.tssrc/gasless/useGaslessReturnToIssuer.tssrc/gasless/useGaslessTransferBeneficiary.tssrc/gasless/useGaslessTransferHolder.tssrc/gasless/useGaslessTransferOwners.tssrc/hooks/useContactForm.tssrc/hooks/useContractFunctionHook.tsxsrc/hooks/useRecaptcha.tssrc/index.csssrc/pages/About/index.tsxsrc/pages/Contact/index.tsxsrc/pages/Partners/index.tsxsrc/pages/Settings/index.tsxtailwind.config.js
💤 Files with no reviewable changes (5)
- e2e/tests/nominate.spec.ts
- e2e/tests/transfer-and-reject-beneficiary.spec.ts
- e2e/setup-contracts.cjs
- e2e/tests/transfer-and-reject-owners.spec.ts
- e2e/tests/reject-return-to-issuer.spec.ts
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/index.css (1)
3873-3886: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
gap: 10pxsilently overrides the existingrow-gap: 0px.Adding
gap: 10pxafterrow-gap: 0pxin.dropdown-btn-framechanges the effective row-gap from0pxto10px(the shorthandgapoverwrites the longhand set immediately above it), flagged by stylelint'sdeclaration-block-no-shorthand-property-overrides. If the intent was to add column spacing only, usecolumn-gap: 10pxinstead ofgap.🎯 Proposed fix
padding: 0px; - row-gap: 0px; - gap: 10px; + column-gap: 10px; + row-gap: 0px;🤖 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 `@src/index.css` around lines 3873 - 3886, Update the .dropdown-btn-frame spacing declarations to use column-gap: 10px instead of the gap shorthand, preserving the existing row-gap: 0px behavior.Source: Linters/SAST tools
🧹 Nitpick comments (4)
src/index.css (1)
2226-2373: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFixed pixel widths in the new gasless error/success blocks have no responsive fallback.
.gasless-error-text(width: 355px),.pay-on-behalf-note(width: 546px),.pay-on-behalf-note-frame(width: 315px), and.pay-on-behalf-note-text(width: 278px) use hard-coded widths with no@mediaadjustment, unlike sibling blocks in this same section (.vr-card-header,.vr-upload-btn) which already handle themax-width: 712pxbreakpoint. On narrow viewports this text/frame combination is likely to overflow or get clipped.🤖 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 `@src/index.css` around lines 2226 - 2373, Replace the fixed widths in .gasless-error-text, .pay-on-behalf-note, .pay-on-behalf-note-frame, and .pay-on-behalf-note-text with responsive sizing, adding the established max-width: 712px breakpoint behavior used by nearby .vr-card-header and .vr-upload-btn styles. Ensure the gasless error and pay-on-behalf content shrink within narrow containers without overflow or clipping.package.json (1)
36-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMove
@testing-library/domintodevDependencies.
@testing-library/domis only pulled into production installs throughdependencies;devDependenciesalready pins the test framework packages, including@testing-library/react, and there are no non-test imports underdependencies.🤖 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 `@package.json` around lines 36 - 38, Move `@testing-library/dom` from dependencies to devDependencies in package.json, keeping its existing version unchanged and grouped with the other testing packages.src/gasless/useGaslessNominate.ts (1)
48-140: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftExtract the shared gasless-eligibility + client-build logic.
This
sendbody (paymaster resolution,hasGaslessConfiggate, delegation + whitelist checks,buildSmartAccountClientcall, error mapping, state transitions) is duplicated almost verbatim across alluseGasless*hooks (useGaslessTransferBeneficiary,useGaslessRejectTransferHolder,useGaslessRejectTransferOwners,useGaslessReturnToIssuer,useGaslessRejectReturned, etc.). Consider a shared helper/factory that takes the gasless/non-gasless callables so each hook only supplies its two trustvc functions. This removes ~9 copies and keeps the eligibility contract in one place.
getRpcUrl(chainId!)is also called twice per send here — reuse the earlierrpcUrl.🤖 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 `@src/gasless/useGaslessNominate.ts` around lines 48 - 140, Extract the duplicated gasless eligibility, paymaster resolution, smart-account client construction, error mapping, and state-transition flow from send into a shared helper or factory used by the useGasless* hooks, with each hook supplying only its gasless and non-gasless callables. Preserve the existing eligibility behavior and trustvc function parameters, and reuse the rpcUrl already resolved during eligibility instead of calling getRpcUrl(chainId!) again when building the client.src/gasless/useGaslessTransferHolder.ts (1)
40-158: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftConsider extracting the shared gasless scaffolding. This eligibility resolution + delegation/whitelist check + gasless-vs-fallback dispatch + state machine is duplicated near-verbatim across all 10
useGasless*hooks. A single parameterized helper (taking the gasless/regular callables and param shape) would remove ~120 duplicated lines per hook and keep the routing logic in one place.🤖 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 `@src/gasless/useGaslessTransferHolder.ts` around lines 40 - 158, Extract the shared gasless flow currently implemented in useGaslessTransferHolder.send—including eligibility resolution, EIP-7702 delegation and whitelist checks, gasless-versus-regular dispatch, and state/error transitions—into one parameterized reusable helper. Update useGaslessTransferHolder and the other useGasless* hooks to provide their operation-specific callables and parameters while preserving existing behavior and hook state APIs.
🤖 Prompt for all review comments with 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.
Inline comments:
In `@e2e/playwright.config.ts`:
- Line 11: Update the Playwright configuration around retries and the
transaction specs so failed CI retries do not reuse mutated Hardhat blockchain
state: either reset/redeploy the chain and wallet before each retry, or disable
retries for the stateful nomination, transfer, reject, and return tests while
preserving retries for unrelated specs.
In `@src/components/common/Tag/Tag.tsx`:
- Line 54: Update the className in the Tag component to replace the undefined
font-urbanist-bold utility with the supported font-urbanist and font-bold
utilities, preserving the other styling classes.
In `@src/components/home/VerifySection/VerifyResult.tsx`:
- Around line 159-161: The successful checkGasless branch in VerifyResult.tsx
must persist the trimmed paymaster value using the trustvc_paymaster_${account}
localStorage key; restore this write before setting gaslessStatus to success. In
ActionSelectionForm.tsx lines 193-203, verify the existing pay-on-behalf note
renders once that key is written; make no direct change there unless required by
the verification.
- Around line 82-93: Update the useEffect delegation check to ignore results
from stale requests when account or chainId changes. Track whether the effect is
still active, only call setIsDelegated for the current check, and clean up that
active state in the effect’s return function; preserve the existing early resets
for missing account or RPC URL.
In `@src/gasless/buildSmartAccountClient.ts`:
- Line 34: Update the Pimlico API key configuration used by
buildSmartAccountClient and VITE_PIMLICO_API_KEY so the key is restricted to the
intended application origin/domain before embedding it in the client-side RPC
URL; preserve the existing chain-specific Pimlico endpoint construction while
ensuring leaked keys cannot be reused from other domains.
In `@src/gasless/useGaslessRejectReturned.ts`:
- Around line 66-121: Update hasGaslessConfig in the gasless eligibility flow to
also require tokenRegistryAddress and tokenId before setting useGasless or
entering rejectReturnedGasless. Preserve the existing whitelist checks and
ensure the gasless branch cannot reach non-null assertions when either consumed
parameter is missing.
In `@src/gasless/useGaslessTransferHolder.ts`:
- Around line 70-74: Restore persistence for validated user-entered paymaster
addresses by re-enabling the localStorage.setItem call in VerifyResult.tsx after
trimming and validating the address, using the trustvc_paymaster_${account} key
consumed by the gasless hooks. The affected read sites require no direct
changes: src/gasless/useGaslessTransferHolder.ts lines 70-74,
src/gasless/useGaslessTransferOwners.ts lines 63-67, and
src/gasless/useGaslessRejectTransferBeneficiary.ts lines 64-67 already read the
stored value correctly.
In `@src/index.css`:
- Around line 15-29: Update the affected `@font-face` rules and selectors in
src/index.css to use unquoted font-family names, including Urbanist and Avenir,
consistent with the rest of the file. In .gasless-address-input-field, remove
the duplicate border-radius declaration. Remove extra blank lines before
declarations in the new check-gasless and pay-on-behalf rules so they satisfy
declaration-empty-line-before.
---
Outside diff comments:
In `@src/index.css`:
- Around line 3873-3886: Update the .dropdown-btn-frame spacing declarations to
use column-gap: 10px instead of the gap shorthand, preserving the existing
row-gap: 0px behavior.
---
Nitpick comments:
In `@package.json`:
- Around line 36-38: Move `@testing-library/dom` from dependencies to
devDependencies in package.json, keeping its existing version unchanged and
grouped with the other testing packages.
In `@src/gasless/useGaslessNominate.ts`:
- Around line 48-140: Extract the duplicated gasless eligibility, paymaster
resolution, smart-account client construction, error mapping, and
state-transition flow from send into a shared helper or factory used by the
useGasless* hooks, with each hook supplying only its gasless and non-gasless
callables. Preserve the existing eligibility behavior and trustvc function
parameters, and reuse the rpcUrl already resolved during eligibility instead of
calling getRpcUrl(chainId!) again when building the client.
In `@src/gasless/useGaslessTransferHolder.ts`:
- Around line 40-158: Extract the shared gasless flow currently implemented in
useGaslessTransferHolder.send—including eligibility resolution, EIP-7702
delegation and whitelist checks, gasless-versus-regular dispatch, and
state/error transitions—into one parameterized reusable helper. Update
useGaslessTransferHolder and the other useGasless* hooks to provide their
operation-specific callables and parameters while preserving existing behavior
and hook state APIs.
In `@src/index.css`:
- Around line 2226-2373: Replace the fixed widths in .gasless-error-text,
.pay-on-behalf-note, .pay-on-behalf-note-frame, and .pay-on-behalf-note-text
with responsive sizing, adding the established max-width: 712px breakpoint
behavior used by nearby .vr-card-header and .vr-upload-btn styles. Ensure the
gasless error and pay-on-behalf content shrink within narrow containers without
overflow or clipping.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: cbfc881d-8cfc-4af2-b925-4f667db255be
⛔ Files ignored due to path filters (11)
package-lock.jsonis excluded by!**/package-lock.jsonpublic/fonts/GilroyBold/font.woffis excluded by!**/*.woffpublic/fonts/GilroyBold/font.woff2is excluded by!**/*.woff2public/fonts/GilroyExtraBold/font.woffis excluded by!**/*.woffpublic/fonts/GilroyExtraBold/font.woff2is excluded by!**/*.woff2public/fonts/GilroyLight/font.woffis excluded by!**/*.woffpublic/fonts/GilroyLight/font.woff2is excluded by!**/*.woff2public/fonts/GilroyMedium/font.woffis excluded by!**/*.woffpublic/fonts/GilroyMedium/font.woff2is excluded by!**/*.woff2public/fonts/Urbanist/Urbanist-Italic-Variable.woff2is excluded by!**/*.woff2public/fonts/Urbanist/Urbanist-Variable.woff2is excluded by!**/*.woff2
📒 Files selected for processing (56)
.github/workflows/e2e.ymle2e/fixtures/local/w3c/tr_accept_surrender.jsone2e/fixtures/local/w3c/tr_reject_surrender.jsone2e/helpers/actions.tse2e/playwright.config.tse2e/setup-contracts.cjse2e/tests/nominate.spec.tse2e/tests/reject-return-to-issuer.spec.tse2e/tests/transfer-and-reject-beneficiary.spec.tse2e/tests/transfer-and-reject-owners.spec.tspackage.jsonpublic/fonts/Urbanist/OFL.txtsrc/components/AssetManagementPanel/AssetManagementForm/FormVariants/ActionSelectionForm/ActionSelectionForm.tsxsrc/components/about/CapabilityCard/CapabilityCard.tsxsrc/components/about/EcosystemCard/EcosystemCard.tsxsrc/components/common/AddressBookOverlay/AddressBookOverlay.tsxsrc/components/common/Button/Button.tsxsrc/components/common/FormAlert/FormAlert.tsxsrc/components/common/Icons/Icons.tsxsrc/components/common/Icons/index.tssrc/components/common/Navbar/Navbar.tsxsrc/components/common/PartnerCard/index.tsxsrc/components/common/Recaptcha/Recaptcha.tsxsrc/components/common/Tag/Tag.tsxsrc/components/common/TextAreaField/TextAreaField.tsxsrc/components/common/TextField/TextField.tsxsrc/components/common/contexts/TokenInformationContext/TokenInformationContext.tsxsrc/components/home/PartnersSection/index.tsxsrc/components/home/VerifySection/VerifyError.tsxsrc/components/home/VerifySection/VerifyResult.tsxsrc/gasless/buildSmartAccountClient.tssrc/gasless/checkDelegation.test.tssrc/gasless/checkDelegation.tssrc/gasless/checkPaymasterWhitelist.test.tssrc/gasless/checkPaymasterWhitelist.tssrc/gasless/gaslessHooks.test.tsxsrc/gasless/index.tssrc/gasless/useGaslessAcceptReturned.tssrc/gasless/useGaslessNominate.tssrc/gasless/useGaslessRejectReturned.tssrc/gasless/useGaslessRejectTransferBeneficiary.tssrc/gasless/useGaslessRejectTransferHolder.tssrc/gasless/useGaslessRejectTransferOwners.tssrc/gasless/useGaslessReturnToIssuer.tssrc/gasless/useGaslessTransferBeneficiary.tssrc/gasless/useGaslessTransferHolder.tssrc/gasless/useGaslessTransferOwners.tssrc/hooks/useContactForm.tssrc/hooks/useContractFunctionHook.tsxsrc/hooks/useRecaptcha.tssrc/index.csssrc/pages/About/index.tsxsrc/pages/Contact/index.tsxsrc/pages/Partners/index.tsxsrc/pages/Settings/index.tsxtailwind.config.js
💤 Files with no reviewable changes (5)
- e2e/tests/nominate.spec.ts
- e2e/tests/transfer-and-reject-beneficiary.spec.ts
- e2e/setup-contracts.cjs
- e2e/tests/transfer-and-reject-owners.spec.ts
- e2e/tests/reject-return-to-issuer.spec.ts
🛑 Comments failed to post (8)
e2e/playwright.config.ts (1)
11-11: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash rg -n 'hardhat_reset|evm_snapshot|evm_revert|beforeEach|test\.retry' e2e .github/workflows/e2e.ymlRepository: TrustVC/trustvc-website
Length of output: 5017
🏁 Script executed:
#!/bin/bash set -e echo "## e2e/playwright.config.ts" cat -n e2e/playwright.config.ts echo echo "## .github/workflows/e2e.yml" cat -n .github/workflows/e2e.yml echo echo "## e2e spec files sizes and snapshot/revert locations" python3 - <<'PY' from pathlib import Path for path in sorted(Path('e2e/tests').glob('*.spec.ts')): text = path.read_text() print(f"{path}: lines={len(text.splitlines())}") for needle in ['hardhat_reset','evm_snapshot','evm_revert','test.beforeEach']: hits = [i+1 for i,line in enumerate(text.splitlines()) if needle in line] if hits: print(f" {needle}: {hits[:10]}{'...' if len(hits)>10 else ''}") PY echo echo "## Relevant e2e helpers/config imports" for f in $(git ls-files e2e/*.ts e2e/**/*.ts); do if rg -n 'hardhat|evm_snapshot|evm_revert|hardhat_reset|hardhatRpcNode|hardhatRpc' "$f" >/dev/null; then echo "### $f" rg -n 'hardhat|evm_snapshot|evm_revert|hardhat_reset|hardhatRpcNode|hardhatRpc' "$f" fi doneRepository: TrustVC/trustvc-website
Length of output: 12015
🏁 Script executed:
#!/bin/bash set -e echo "## Nominate spec" cat -n e2e/tests/nominate.spec.ts echo echo "## Transfer and reject owner/beneficiary specs" for f in e2e/tests/transfer-and-reject-owners.spec.ts e2e/tests/transfer-and-reject-beneficiary.spec.ts e2e/tests/transfer-and-reject-holder.spec.ts e2e/tests/accept-return-to-issuer.spec.ts e2e/tests/reject-return-to-issuer.spec.ts; do echo "### $f" sed -n '1,120p' "$f" | cat -n done echo echo "## Actions helpers around hardhat RPCs" cat -n e2e/helpers/actions.ts | sed -n '140,190p'Repository: TrustVC/trustvc-website
Length of output: 29016
Reset blockchain state before CI retries for transaction tests.
retries: 2reruns failed tests against the same background Hardhat node, but the transaction specs don’t snapshot/revert or reset state. If a nomination, transfer, reject, or return flow fails after the contract transaction is accepted, the retry sees mutated on-chain state. Reset/redeploy the chain and wallet per retry, or disable retries for these stateful specs.🤖 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 `@e2e/playwright.config.ts` at line 11, Update the Playwright configuration around retries and the transaction specs so failed CI retries do not reuse mutated Hardhat blockchain state: either reset/redeploy the chain and wallet before each retry, or disable retries for the stateful nomination, transfer, reject, and return tests while preserving retries for unrelated specs.src/components/common/Tag/Tag.tsx (1)
54-54: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash rg -n "urbanist-bold|fontFamily|font-urbanist" tailwind.config.js src/components/common/Tag/Tag.tsxRepository: TrustVC/trustvc-website
Length of output: 320
🏁 Script executed:
#!/bin/bash set -e echo "== Candidate config files ==" git ls-files | rg '(^|/)(tailwind\.config\.(js|cjs|mjs|ts)|postcss\.config\.(js|cjs|mjs|ts)|package\.json)$|(^|/)styles/|(^|/)src/' echo echo "== Tailwind config around fontFamily ==" sed -n '40,80p' tailwind.config.js echo echo "== All font-family references ==" rg -n 'font-family|font-urba|urba|urbanist|fontFamily' -S . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | head -200 echo echo "== Tag component ==" sed -n '1,90p' src/components/common/Tag/Tag.tsxRepository: TrustVC/trustvc-website
Length of output: 50380
🏁 Script executed:
#!/bin/bash set -e echo "== Relevant Tailwind config excerpt ==" sed -n '45,65p' tailwind.config.js echo echo "== Tag component excerpt ==" sed -n '1,80p' src/components/common/Tag/Tag.tsx echo echo "== Focused text search ==" rg -n --hidden --glob '!*.gz' --glob '!*.map' '^.*(fontFamily|font-urba|urbanist-bold|font-urbanist)$|^.*(fontFamily|font-urba|urbanist-bold|font-urbanist)"|^.*(fontFamily|font-urba|urbanist-bold|font-urbanist):' . | head -200Repository: TrustVC/trustvc-website
Length of output: 2160
Use a defined Tailwind font utility.
font-urbanist-boldhas no matchingfontFamilykey intailwind.config.js, so this class won’t generate the intended font. Usefont-urbanist font-boldor defineurbanist-boldexplicitly.🤖 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 `@src/components/common/Tag/Tag.tsx` at line 54, Update the className in the Tag component to replace the undefined font-urbanist-bold utility with the supported font-urbanist and font-bold utilities, preserving the other styling classes.src/components/home/VerifySection/VerifyResult.tsx (2)
82-93: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Guard against stale delegation results.
checkEIP7702Delegation(...).then(setIsDelegated)has no cleanup, so ifaccount/chainIdchange while a check is in flight, a late-resolving promise can overwriteisDelegatedwith a value for the previous wallet/chain.🛠️ Proposed fix
useEffect(() => { if (!account || !chainId) { setIsDelegated(false) return } const rpcUrl = getRpcUrl(chainId) if (!rpcUrl) { setIsDelegated(false) return } - checkEIP7702Delegation(account, rpcUrl).then(setIsDelegated) + let active = true + checkEIP7702Delegation(account, rpcUrl).then(result => { + if (active) setIsDelegated(result) + }) + return () => { + active = false + } }, [account, chainId])📝 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.useEffect(() => { if (!account || !chainId) { setIsDelegated(false) return } const rpcUrl = getRpcUrl(chainId) if (!rpcUrl) { setIsDelegated(false) return } let active = true checkEIP7702Delegation(account, rpcUrl).then(result => { if (active) setIsDelegated(result) }) return () => { active = false } }, [account, chainId])🤖 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 `@src/components/home/VerifySection/VerifyResult.tsx` around lines 82 - 93, Update the useEffect delegation check to ignore results from stale requests when account or chainId changes. Track whether the effect is still active, only call setIsDelegated for the current check, and clean up that active state in the effect’s return function; preserve the existing early resets for missing account or RPC URL.
159-161: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Paymaster persistence is disabled — commented-out
setItembreaks the pay-on-behalf feature. On successcheckGaslessno longer writestrustvc_paymaster_${account}tolocalStorage, so every consumer that reads that key is permanently inert: the auto-verify-on-delegation effect (VerifyResult.tsxL191-197) never finds a stored value, and the pay-on-behalf note never renders.
src/components/home/VerifySection/VerifyResult.tsx#L159-L161: restorelocalStorage.setItem(\trustvc_paymaster_${account}`, trimmed)` on the success branch (or remove the dependent read paths if persistence is intentionally dropped).src/components/AssetManagementPanel/AssetManagementForm/FormVariants/ActionSelectionForm/ActionSelectionForm.tsx#L193-L203: this note only appears once the key above is written; confirm it renders after the fix, otherwise this block is dead UI.📍 Affects 2 files
src/components/home/VerifySection/VerifyResult.tsx#L159-L161(this comment)src/components/AssetManagementPanel/AssetManagementForm/FormVariants/ActionSelectionForm/ActionSelectionForm.tsx#L193-L203🤖 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 `@src/components/home/VerifySection/VerifyResult.tsx` around lines 159 - 161, The successful checkGasless branch in VerifyResult.tsx must persist the trimmed paymaster value using the trustvc_paymaster_${account} localStorage key; restore this write before setting gaslessStatus to success. In ActionSelectionForm.tsx lines 193-203, verify the existing pay-on-behalf note renders once that key is written; make no direct change there unless required by the verification.src/gasless/buildSmartAccountClient.ts (1)
34-34: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== Locate file ==" git ls-files | rg '(^|/)buildSmartAccountClient\.ts$|src/gasless' || true echo echo "== File outline ==" ast-grep outline src/gasless/buildSmartAccountClient.ts || true echo echo "== Relevant file content ==" cat -n src/gasless/buildSmartAccountClient.ts | sed -n '1,120p' echo echo "== References to VITE_PIMLICO_API_KEY and buildSmartAccountClient ==" rg -n "VITE_PIMLICO_API_KEY|pimlicoApiKey|buildSmartAccountClient" .Repository: TrustVC/trustvc-website
Length of output: 8814
Restrict the embedded Pimlico API key before exposing it in client URLs.
The Pimlico key is read from
VITE_PIMLICO_API_KEY, passed into bundled client code, and added to Pimlico RPC requests as?apikey=.... Make the Pimlico API key origin/domain-restricted so a leaked key cannot be reused from other pages/domains.🤖 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 `@src/gasless/buildSmartAccountClient.ts` at line 34, Update the Pimlico API key configuration used by buildSmartAccountClient and VITE_PIMLICO_API_KEY so the key is restricted to the intended application origin/domain before embedding it in the client-side RPC URL; preserve the existing chain-specific Pimlico endpoint construction while ensuring leaked keys cannot be reused from other domains.src/gasless/useGaslessRejectReturned.ts (1)
66-121: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "Files matching useGaslessRejectReturned:" fd -a 'useGaslessRejectReturned\.ts$' . || true file=$(fd 'useGaslessRejectReturned\.ts$' . | head -n1) if [ -n "${file:-}" ]; then echo "--- outline ---" ast-grep outline "$file" || true echo "--- relevant lines ---" nl -ba "$file" | sed -n '1,180p' fi echo "--- related gasless reject/confirm hooks ---" rg -n "useGasless|gaslessRejectReturned|rejectReturned|titleEscrowAddress|tokenRegistryAddress" --iglob '*.ts' --iglob '*.tsx' .Repository: TrustVC/trustvc-website
Length of output: 714
🏁 Script executed:
#!/bin/bash set -euo pipefail file=$(fd 'useGaslessRejectReturned\.ts$' . | head -n1) if [ -n "${file:-}" ]; then python3 - <<'PY' "$file" import pathlib, re, sys p = pathlib.Path(sys.argv[1]) text = p.read_text() checks = { "has gaslessConfig": "hasGaslessConfig" in text, "checks titleEscrowAddress": "!!titleEscrowAddress" in text, "checks tokenRegistryAddress": "!!tokenRegistryAddress" in text, "checks tokenId": "!!tokenId" in text, "gasless branch uses tokenRegistryAddress assertion": "tokenRegistryAddress as `0x${string}`" in text, "gasless branch uses tokenId assertion": "tokenId: tokenId!" in text, "whitelist uses titleEscrowAddress assertion": "isTitleEscrowAuthorized" in text and "titleEscrowAddress!" in text, "fallback guards tokenRegistryAddress": "if (!tokenRegistryAddress)" in text, } for k,v in checks.items(): print(f"{k}: {v}") # Extract conditional guards present before set hasGaslessConfig; print concise relevant assertions only. for m in re.finditer(r"\bhasGaslessConfig\s*=([\s\S]*?)\n\s+if \(hasGaslessConfig\)", text): body = m.group(1) assertions = re.findall(r"\!\!([A-Za-z_$][A-Za-z0-9_$]*\)?|[^()]+?)[ \t]*\s*(?:,|\n|$)", body) print(f"guard assertions: {', '.join(asertions)}") PY fiRepository: TrustVC/trustvc-website
Length of output: 586
🏁 Script executed:
#!/bin/bash set -euo pipefail file="/home/jailuser/git/src/gasless/useGaslessRejectReturned.ts" echo "--- file content ---" awk '{printf "%6d %s\n", NR, $0}' "$file" echo "--- precise invariant checks ---" python3 - "$file" <<'PY' import sys, re p = sys.argv[1] text = open(p, encoding="utf-8").read() guards = [] m = re.search(r"const hasGaslessConfig\s*=[\s\S]*?\n\s+if \(hasGaslessConfig\)", text) if m: guards = re.findall(r"\!\!([^,\n)]+?)\b", m.group(0)) print("hasGaslessConfig guard checks:", guards) for term in ["tokenRegistryAddress", "tokenId", "titleEscrowAddress"]: print(f"checks {term} in guard: {'!!' + term in guards}") sections = { "gaslessCallOptions": re.search(r"if \(useGasless\) \{[\s\S]*?setTransactionHash\(txHash\)\s*\}", text), "fallback": re.search(r"} else \{[\s\S]*?if \(!tokenRegistryAddress\)", text), } for label, sec in sections.items(): print(f"{label}: {sec is not None}") if sec: s = sec.group(0) print(f" contains tokenRegistryAddress!: {'tokenRegistryAddress!' in s}") print(f" contains tokenId!: {'tokenId!' in s}") print(f" contains titleEscrowAddress!: {'titleEscrowAddress!' in s}") PYRepository: TrustVC/trustvc-website
Length of output: 6324
Require the consumed gasless params before entering the gasless path.
hasGaslessConfigenables gasless only fromtitleEscrowAddress, butrejectReturnedGaslessneedstokenRegistryAddressandtokenId. Add these to the eligibility gate, or gate the whitelist/executive target behind the actual required params, so the path doesn’t proceed with assertions on missing values.🤖 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 `@src/gasless/useGaslessRejectReturned.ts` around lines 66 - 121, Update hasGaslessConfig in the gasless eligibility flow to also require tokenRegistryAddress and tokenId before setting useGasless or entering rejectReturnedGasless. Preserve the existing whitelist checks and ensure the gasless branch cannot reach non-null assertions when either consumed parameter is missing.src/gasless/useGaslessTransferHolder.ts (1)
70-74: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Find any writer of the paymaster localStorage key rg -nP "trustvc_paymaster_" -g '!**/*.test.*' -C2Repository: TrustVC/trustvc-website
Length of output: 161
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== tracked files matching relevant names ==" git ls-files | rg '(^|/)Use(Gasless|Transfer)Result\.tsx$|(^|/)useGasless(Holder|Owners|RejectTransferBeneficiary|TransferOwners|TransferBeneficiary)\.(ts|tsx)$|(/gasless/|gasless/)' || true echo echo "== occurrences of paymaster key (all files) ==" rg -n "paymaster" . || true echo echo "== VerifyResult candidates ==" git ls-files | rg 'VerifyResult\.tsx$' || true echo echo "== git diff status/stat ==" git diff --statRepository: TrustVC/trustvc-website
Length of output: 6598
Restore persistance for user-entered paymaster addresses. The gasless hooks and stored-auto-verify path read
localStorage.getItem('trustvc_paymaster_${account}'), but the matching write inVerifyResult.tsxremains commented out, so all reads fall back toPAYMASTER_ADDRESSeven after whitelist verification succeeds. Re-enable thelocalStorage.setItem(...)after trimming/validation.📍 Affects 3 files
src/gasless/useGaslessTransferHolder.ts#L70-L74(this comment)src/gasless/useGaslessTransferOwners.ts#L63-L67src/gasless/useGaslessRejectTransferBeneficiary.ts#L64-L67🤖 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 `@src/gasless/useGaslessTransferHolder.ts` around lines 70 - 74, Restore persistence for validated user-entered paymaster addresses by re-enabling the localStorage.setItem call in VerifyResult.tsx after trimming and validating the address, using the trustvc_paymaster_${account} key consumed by the gasless hooks. The affected read sites require no direct changes: src/gasless/useGaslessTransferHolder.ts lines 70-74, src/gasless/useGaslessTransferOwners.ts lines 63-67, and src/gasless/useGaslessRejectTransferBeneficiary.ts lines 64-67 already read the stored value correctly.src/index.css (1)
15-29: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Stylelint errors flagged in the new/changed CSS: quoted font-family names and a duplicate declaration.
Stylelint (17.14.0) reports several real errors in the added/changed code:
font-family-name-quotes: quotes around'Urbanist'/'Avenir'at lines 17, 26, 77, 2143, 2260, 2322, 2362, 3782, 4114, 4188, 4715 (most other new declarations in this file correctly useUrbanist, sans-serifunquoted, so this is also an internal inconsistency).declaration-block-no-duplicate-properties:border-radius: 8px;is declared twice in.gasless-address-input-field(~2186-2190).declaration-empty-line-before: multiple blank lines before declarations in the newcheck-gasless/pay-on-behalfrules (2208, 2293, 2322, 2342, 2345, 2355, 2362, 2368).These are cheap to fix and, depending on the CI pipeline's lint gate, may currently be failing the build.
🎯 Example fixes
`@font-face` { - font-family: 'Urbanist'; + font-family: Urbanist;background: `#ffffff`; border-radius: 8px; /* TrustVC/Stroke/Base/Enabled */ border: 1px solid `#a9b2bb`; - border-radius: 8px; }Also applies to: 74-89, 2078-2372, 3779-3784, 4109-4117, 4184-4189, 4708-4719
🧰 Tools
🪛 Stylelint (17.14.0)
[error] 17-17: Expected no quotes around "Urbanist" (font-family-name-quotes)
(font-family-name-quotes)
[error] 26-26: Expected no quotes around "Urbanist" (font-family-name-quotes)
(font-family-name-quotes)
🤖 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 `@src/index.css` around lines 15 - 29, Update the affected `@font-face` rules and selectors in src/index.css to use unquoted font-family names, including Urbanist and Avenir, consistent with the rest of the file. In .gasless-address-input-field, remove the duplicate border-radius declaration. Remove extra blank lines before declarations in the new check-gasless and pay-on-behalf rules so they satisfy declaration-empty-line-before.Source: Linters/SAST tools
Lock file was missing @sentry/react, @sentry/vite-plugin, and react-ga4 that were added during the upstream merge, causing npm ci to fail in CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ibility The two whitelist-fallback tests require hasGaslessConfig=true (PIMLICO_API_KEY set) to reach the whitelist check. In CI without a .env file the module-level constant is undefined, so the hook skips delegation/whitelist entirely and the assertions on checkPaymasterWhitelist always failed. Moving them into the gasless section which uses vi.stubEnv + vi.resetModules + dynamic imports ensures PIMLICO_API_KEY is set when these tests run. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…talled synpress-cache imports playwright-core at runtime. Since @playwright/test was only a transitive peer dep of synpress (not listed directly), it was not installed under legacy-peer-deps, causing ERR_MODULE_NOT_FOUND in CI during the e2e:setup-wallet step. Pinning to 1.48.2 matches the version already resolved in the lock file.
The pattern /verify-.*\.spec\.ts/ only matched files starting with "verify-", leaving amoy-verify.spec.ts and pol-verify.spec.ts in the main MetaMask suite. Those specs hit external RPC endpoints (Amoy/Polygon mainnet) which are unreliable in CI and have no MetaMask dependency. Widened to /.*verify.*\.spec\.ts/ so all verify specs (local, amoy, pol) run only via playwright.verify.config.ts.
E2E runs on every push to main/develop were expensive and unnecessary. Keeping only pull_request (gates PRs) and workflow_dispatch (manual runs).
…ty chain - @testing-library/dom belongs in devDependencies (test-only, not shipped) - retries disabled in playwright.config.ts: every spec mutates Hardhat chain state (transfer/reject/return), so a retry after partial failure hits an already-modified chain and fails for a different reason — retries here give false signal, not recovery Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 20
🧹 Nitpick comments (14)
package.json (1)
37-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCaret range on a beta pre-release can silently jump to an unrelated stable release.
^2.15.0-beta.2desugars to>=2.15.0-beta.2 <3.0.0. Per npm semver rules, the prerelease-tuple restriction only limits which prerelease versions satisfy the range — once a stable2.15.x/2.16.x/... version is published, it satisfies the range too (stable versions aren't gated by the prerelease-tuple rule). A futurenpm installcould pull in an untested stable release with different gasless API behavior instead of the beta this PR was built and tested against.♻️ Suggested fix: pin the exact beta
- "`@trustvc/trustvc`": "^2.15.0-beta.2", + "`@trustvc/trustvc`": "2.15.0-beta.2",🤖 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 `@package.json` at line 37, Update the `@trustvc/trustvc` dependency in package.json from the caret range to the exact tested beta version 2.15.0-beta.2, preventing installation from selecting later stable or prerelease versions..npmrc (1)
1-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winGlobal
legacy-peer-deps=truemasks peer-dependency conflicts project-wide.This setting disables peer-dependency validation for every install, not just for the new
permissionless/viem/beta@trustvc/trustvcadditions. If it's needed because of a specific peer-dep mismatch (e.g.permissionless'sviempeer range vs. theviemversion pinned directly), consider scoping the fix viaoverrides/resolutionsinstead, so future genuine peer conflicts aren't silently hidden.🤖 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 @.npmrc around lines 1 - 2, Remove the global legacy-peer-deps setting from .npmrc and resolve the specific permissionless/viem/@trustvc/trustvc peer mismatch through targeted package overrides or resolutions in the project’s dependency configuration.src/components/common/Icons/Icons.tsx (1)
235-267: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
strokeprop is only honored by one of the three shapes.The
<line>and<circle>hardcode#FF8200, so passing a customstrokeyields a two-tone icon. Also worth addingaria-hidden="true"asCheckCircledoes, since this renders purely decoratively beside text.🎨 Proposed fix
xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" {...props} @@ - stroke="`#FF8200`" + stroke={stroke} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /> - <circle cx="10.5357" cy="15.1786" r="0.535714" fill="`#FF8200`" /> + <circle cx="10.5357" cy="15.1786" r="0.535714" fill={stroke} />🤖 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 `@src/components/common/Icons/Icons.tsx` around lines 235 - 267, Update InfoMsgIcon so the line and circle use the component’s stroke prop instead of hardcoded `#FF8200`, keeping all three shapes consistently colored; also add aria-hidden="true" to the SVG for decorative use.src/gasless/useGaslessTransferHolder.ts (1)
153-154: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUnnecessary
exhaustive-depssuppression.
resetis auseCallbackwith an empty dep array, so it's stable and can just be listed in the deps instead of disabling the rule. The other nine hooks inline the three setters rather than callingreset(); picking one style would remove the need for this suppression entirely.🤖 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 `@src/gasless/useGaslessTransferHolder.ts` around lines 153 - 154, Remove the unnecessary exhaustive-deps suppression in the hook containing reset, and include the stable reset callback in that effect’s dependency array. Keep the dependency behavior consistent with the surrounding hooks, avoiding inline setter duplication unless needed to eliminate the reset call.src/components/home/VerifySection/VerifyResult.tsx (3)
131-131: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winRemove the debug logging before merge.
These
console.log/warn/errorcalls ship the connected wallet address (viaresult/titleEscrowAddress), the resolved RPC endpoint, and raw errors to the browser console on every verification. Wallet addresses are user identifiers; drop these or route them through the project's logger at debug level.Also applies to: 149-149, 157-157, 163-168, 173-173
🤖 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 `@src/components/home/VerifySection/VerifyResult.tsx` at line 131, Remove the debug console logging in the verification flow around the checkGasless logic, including the calls at the referenced locations that expose rpcUrl, chainId, result, titleEscrowAddress, or raw errors. Do not log these values to the browser console; if diagnostics are required, route them through the project logger at debug level without exposing wallet addresses or sensitive error details.
21-21: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse a relative import path.
'../../../../src/components/icons/info'walks up out of the tree and back down throughsrc/, unlike every other import in this file.'../../icons/info'resolves to the same module.🤖 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 `@src/components/home/VerifySection/VerifyResult.tsx` at line 21, Update the InfoIcon import in VerifyResult.tsx to use the shorter relative path ../../icons/info, matching the surrounding imports and resolving to the same module.
172-185: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winError classification by substring matching is fragile.
Any thrown error that doesn't contain
network/fetchis reported to the user as "Invalid Paymaster Address" — including a revertedownerOf(tokenId)read, a wrong-chain RPC, or a contract at the paymaster address that lacksauthorizedCallers. Consider distinguishing theownerOfread from the whitelist read so the message reflects which step actually failed.🤖 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 `@src/components/home/VerifySection/VerifyResult.tsx` around lines 172 - 185, The error handling in the gasless verification flow incorrectly classifies all non-network failures as invalid paymaster addresses. Update the relevant verification function and distinguish failures from the token ownerOf read versus the paymaster whitelist/authorizedCallers read, assigning an error message that reflects the failed step while preserving network-error handling.src/gasless/checkDelegation.ts (1)
12-30: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd a request timeout; consider reusing viem instead of raw
fetch.This runs inline in every
send()before the transaction path. An unresponsive RPC has no timeout here, so the user is stuck inINITIALIZEDindefinitely. Also,checkPaymasterWhitelist.tsalready uses viem'screatePublicClient;getCodewould give the same result with consistent transport/retry handling.⏱️ Minimal fix: bound the request
const response = await fetch(rpcUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, + signal: AbortSignal.timeout(10_000), body: JSON.stringify({🤖 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 `@src/gasless/checkDelegation.ts` around lines 12 - 30, Bound the RPC request in the delegation check so an unresponsive endpoint cannot leave send() stuck indefinitely. Update the checkDelegation flow around the raw fetch to apply the project’s established request-timeout approach, while preserving the existing false-on-error behavior; preferably reuse the viem createPublicClient/getCode pattern already used by checkPaymasterWhitelist.ts for consistent transport handling.src/gasless/useGaslessNominate.ts (1)
106-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winStructural
ascast onsmartAccountClienthides a real contract.Casting to an inline
{ sendTransaction(...) }shape suppresses any future signature drift in eitherpermissionlessornominateGasless. Define the expected client interface once insrc/gasless/and reuse it across hooks.🤖 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 `@src/gasless/useGaslessNominate.ts` around lines 106 - 117, Replace the inline structural cast on smartAccountClient in the nominateGasless call with a shared client interface defined in the gasless module. Update nominateGasless and related hooks to reuse that interface, ensuring the sendTransaction signature remains checked consistently and future contract drift is exposed by TypeScript.src/gasless/useGaslessRejectTransferHolder.ts (1)
77-106: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
getRpcUrl(chainId!)is computed twice; reuse the value from Line 78.Minor, but the second call at Line 104 also re-applies a non-null assertion on a value already proven non-null inside the
if (rpcUrl)block. HoistingrpcUrlabove thehasGaslessConfigbranch removes both.🤖 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 `@src/gasless/useGaslessRejectTransferHolder.ts` around lines 77 - 106, Reuse the existing rpcUrl variable from the gasless configuration flow when calling buildSmartAccountClient, instead of invoking getRpcUrl(chainId!) again and reapplying a non-null assertion. Hoist or scope rpcUrl so it remains available after the hasGaslessConfig checks while preserving the existing validation that prevents the gasless path without a valid RPC URL.src/gasless/buildSmartAccountClient.ts (1)
59-77: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueHardcoded paymaster gas limits and empty
paymasterDataassume a permissionless (non-signature-verifying) paymaster.If the platform paymaster ever requires signed data or the postOp cost changes, these constants will silently under/over-estimate. Consider sourcing them from config, or querying the paymaster service, rather than baking magic numbers into the client.
🤖 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 `@src/gasless/buildSmartAccountClient.ts` around lines 59 - 77, Update the paymaster configuration in buildSmartAccountClient, specifically getPaymasterStubData and getPaymasterData, to obtain paymasterData and gas limits from the configured paymaster source or service instead of returning hardcoded empty data and magic-number limits. Ensure both methods use the same authoritative values while preserving isFinal on the stub response.src/gasless/gaslessHooks.test.tsx (3)
763-775: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value"State transitions" only asserts the terminal state.
INITIALIZEDandPENDING_CONFIRMATIONare never observed, so a hook that jumped straight toCONFIRMEDwould pass. Capture intermediate states by resolving the mocked tx from a deferred promise.🤖 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 `@src/gasless/gaslessHooks.test.tsx` around lines 763 - 775, Strengthen the “state transitions” test for useGaslessTransferHolder by making the mocked transaction confirmation deferred, then assert INITIALIZED before sending and PENDING_CONFIRMATION after send begins but before the deferred transaction resolves. Resolve the deferred transaction and retain the final CONFIRMED assertion after the send completes.
976-1028: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winThis describe block does not test what its title claims.
All three tests assert only
state === 'CONFIRMED', and the inline comment at Line 984 concedes the paymaster read path is actually verified elsewhere. The tests at Line 998 and Line 1013 are functionally identical to each other. The real assertion — that thelocalStoragevalue wins overPAYMASTER_ADDRESS— needs the gasless-path hooks plus acheckPaymasterWhitelistargument check, which is already done once at Line 540.Suggest collapsing to a single meaningful test in the gasless block that stubs
VITE_PAYMASTER_ADDRESSto a sentinel and asserts thelocalStoragevalue takes precedence.🤖 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 `@src/gasless/gaslessHooks.test.tsx` around lines 976 - 1028, Replace the three redundant tests in the describe block with one gasless-path test that configures a sentinel VITE_PAYMASTER_ADDRESS, stores a different paymaster in localStorage, and asserts checkPaymasterWhitelist receives the localStorage value as resolvedPaymasterAddress. Reuse the existing gasless setup and assertion pattern near the earlier checkPaymasterWhitelist test, and remove the state-only fallback tests.
74-80: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueVerify the
ACCOUNTreference inside the hoistedvi.mockfactory.
vi.mockfactories are hoisted above theconst ACCOUNTdeclaration at Line 121. This is safe only becauseACCOUNTis dereferenced lazily whenuseProviderContext()is invoked duringrenderHook, not when the factory runs. It is fragile — moving the constant or making the mock eager reintroduces a TDZ error. Considervi.hoistedforACCOUNTalongside the other hoisted values.Also applies to: 121-129
🤖 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 `@src/gasless/gaslessHooks.test.tsx` around lines 74 - 80, Move the ACCOUNT test value into a vi.hoisted declaration alongside the other hoisted values, and use that hoisted symbol in the useProviderContext mock factory and affected test setup. Remove the later const ACCOUNT declaration while preserving the existing account value and mock behavior.
🤖 Prompt for all review comments with 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.
Inline comments:
In
`@src/components/AssetManagementPanel/AssetManagementForm/FormVariants/ActionSelectionForm/ActionSelectionForm.tsx`:
- Line 199: Update the user-facing text in ActionSelectionForm from “all
transaction” to “all transactions,” leaving the surrounding behavior unchanged.
- Around line 193-203: Replace the direct localStorage lookup in
ActionSelectionForm’s render with shared reactive paymaster state, preferably
via a usePaymasterAddress(account) hook or existing context backed by the same
trustvc_paymaster key used by the gasless hooks. Ensure VerifyResult updates
that state when the key is written so the pay-on-behalf note re-renders
immediately, while preserving the existing account guard and note behavior.
In `@src/components/home/VerifySection/VerifyResult.tsx`:
- Line 160: The trustvc_paymaster_${account} localStorage contract is broken
because its writer is disabled and consumers do not react to updates. In
src/components/home/VerifySection/VerifyResult.tsx:160-160, restore the
successful-verification setItem and remove the key on failure; in
src/gasless/useGaslessTransferBeneficiary.ts:65-68, make no direct change, as
the shared fix should cover all useGasless* hooks; extract the key and lookup
into one shared helper; and in
src/components/AssetManagementPanel/AssetManagementForm/FormVariants/ActionSelectionForm/ActionSelectionForm.tsx:193-203,
replace the render-time getItem with the helper backed by React state so
post-mount writes update the indicator.
- Around line 82-93: Guard the async result in the useEffect that calls
checkEIP7702Delegation so only the latest account and chainId request can update
isDelegated. Track whether the effect is still active and prevent setIsDelegated
after cleanup, while preserving the existing reset behavior for missing accounts
or RPC URLs.
- Around line 366-397: Update the paymaster address input in VerifyResult so it
has a persistent programmatic label rather than relying on the placeholder, and
connect the gasless error message to the input with matching accessible
identifiers. Mark the input’s invalid state when gaslessStatus is error and
ensure the associated error text is announced by assistive technologies.
In `@src/gasless/checkPaymasterWhitelist.ts`:
- Around line 21-36: Update the whitelist-checking function around publicClient
and the parallel authorizedCallers/authorizedTitleEscrows reads to validate
paymasterAddress, userAddress, and titleEscrowAddress before casting or calling
readContract, and use a chain-configured client rather than a chain-less
createPublicClient. Ensure invalid addresses or failed contract reads are caught
and returned as an ineligible result so callers can continue through the paid
path instead of propagating the error.
In `@src/gasless/gaslessHooks.test.tsx`:
- Around line 921-964: Update the “clears state after a successful transaction”
test to explicitly mock checkEIP7702Delegation as resolving false before
rendering useGaslessNominate, ensuring it always exercises the fallback path
regardless of VITE_PIMLICO_API_KEY.
In `@src/gasless/useGaslessAcceptReturned.ts`:
- Line 1: Extract the duplicated gasless eligibility and dispatch setup from
useGaslessAcceptReturned into a shared helper or hook, such as
useGaslessEligibility, returning useGasless and smartAccountClient after
resolving configuration, validating delegation and whitelist status, and
building the client. Update useGaslessAcceptReturned and
useGaslessRejectTransferBeneficiary to consume this result while retaining only
their action-specific gasless/non-gasless calls and parameters.
- Line 1: Update the eligibility blocks in useGaslessAcceptReturned and
useGaslessRejectTransferBeneficiary to locally catch errors from
checkEIP7702Delegation and checkPaymasterWhitelist, keep useGasless false when
either check fails, and continue into the existing paid-transaction path instead
of reaching the outer send catch that sets ERROR. Preserve current gasless
behavior when eligibility checks succeed.
- Around line 66-92: Update hasGaslessConfig in useGaslessAcceptReturned to
validate tokenRegistryAddress instead of, or in addition to, titleEscrowAddress,
matching the required arguments for acceptReturnedGasless. Ensure the gasless
path is only selected when tokenRegistryAddress is present, preserving the
fallback branch’s existing missing-address handling.
In `@src/gasless/useGaslessNominate.ts`:
- Around line 62-73: The resolved paymaster address in useGaslessNominate must
not be trusted directly from localStorage. Validate its address format and
require it to match the configured allowlist of approved platform paymasters
before using it in hasGaslessConfig or buildSmartAccountClient; otherwise fall
back to no usable paymaster configuration.
- Around line 57-93: Wrap the gasless eligibility checks within the main try—
including getRpcUrl, checkEIP7702Delegation, and checkPaymasterWhitelist— in a
nested try/catch that sets useGasless to false on any RPC failure. Keep the
outer transaction error handling unchanged so eligibility failures fall back to
the paid path instead of setting the hook state to ERROR.
In `@src/gasless/useGaslessRejectReturned.ts`:
- Around line 66-72: Update hasGaslessConfig in useGaslessRejectReturned to also
require tokenRegistryAddress and tokenId before selecting the gasless path. Keep
the existing account, titleEscrowAddress, paymaster, API key, chain, and
ethereum checks, and ensure rejectReturnedGasless is only called when all
asserted arguments are present.
In `@src/gasless/useGaslessRejectTransferOwners.ts`:
- Around line 50-142: Extract a shared createGaslessHook factory that resolves
paymaster eligibility and builds the smart-account client inside a separate
try/catch, defaulting to the direct transaction path on eligibility failures.
Apply it to src/gasless/useGaslessRejectTransferOwners.ts lines 50-142 using
rejectTransferOwners/rejectTransferOwnersGasless,
src/gasless/useGaslessNominate.ts lines 57-93 using nominate/nominateGasless and
NominateParams, src/gasless/useGaslessRejectTransferHolder.ts lines 77-106 using
rejectTransferHolder/rejectTransferHolderGasless, and
src/gasless/useGaslessReturnToIssuer.ts lines 56-92 using
returnToIssuer/returnToIssuerGasless; remove each duplicated eligibility,
paymaster, and client-building implementation while preserving each hook’s
required fields and transaction arguments.
In `@src/gasless/useGaslessTransferBeneficiary.ts`:
- Around line 60-107: Extract the shared gasless eligibility and smart-account
construction flow from the hook containing setState('INITIALIZED'), including
paymaster resolution, hasGaslessConfig checks, delegation, whitelist validation,
and buildSmartAccountClient, into a reusable useGaslessExecutor or
resolveGaslessExecution helper. Update each useGasless* hook to call this helper
and handle its { smartAccountClient } | null result before performing its
action-specific execution, preserving existing eligibility behavior.
- Around line 137-140: Update the catch block in the gasless transfer flow to
ensure setErrorMessage receives a non-empty message when getMetaMaskErrorMessage
returns an empty string for unknown bundler, paymaster, or EIP-7702 errors.
Preserve known MetaMask/ethers mappings, and fall back to the caught error’s
available message or a generic gasless transfer failure message before setting
state to ERROR.
In `@src/index.css`:
- Around line 2307-2332: Merge the two .check-gasless-content-success-text
rulesets into a single declaration, preserving all effective properties
including flex-direction, padding, and gap alongside the typography and layout
styles. Remove the duplicate selector while keeping the existing styling
behavior unchanged.
- Line 2143: Update the CSS declarations in src/index.css to remove quotes from
the Avenir font-family name and eliminate the flagged empty lines before
declarations at the referenced locations; run stylelint --fix to apply the
required formatting consistently.
- Around line 2334-2360: Update the .pay-on-behalf-note,
.pay-on-behalf-note-frame, and .pay-on-behalf-note-text rules to remove fixed
width and height constraints that can overflow or clip text. Use responsive
max-width values compatible with the .dropdown-btn-frame parent and height:
auto, while preserving the existing flex layout and spacing.
- Around line 3881-3882: Replace the shorthand gap declaration in the affected
style rule with column-gap: 10px, preserving row-gap: 0px so only horizontal
spacing is applied and the shorthand override warning is resolved.
---
Nitpick comments:
In @.npmrc:
- Around line 1-2: Remove the global legacy-peer-deps setting from .npmrc and
resolve the specific permissionless/viem/@trustvc/trustvc peer mismatch through
targeted package overrides or resolutions in the project’s dependency
configuration.
In `@package.json`:
- Line 37: Update the `@trustvc/trustvc` dependency in package.json from the caret
range to the exact tested beta version 2.15.0-beta.2, preventing installation
from selecting later stable or prerelease versions.
In `@src/components/common/Icons/Icons.tsx`:
- Around line 235-267: Update InfoMsgIcon so the line and circle use the
component’s stroke prop instead of hardcoded `#FF8200`, keeping all three shapes
consistently colored; also add aria-hidden="true" to the SVG for decorative use.
In `@src/components/home/VerifySection/VerifyResult.tsx`:
- Line 131: Remove the debug console logging in the verification flow around the
checkGasless logic, including the calls at the referenced locations that expose
rpcUrl, chainId, result, titleEscrowAddress, or raw errors. Do not log these
values to the browser console; if diagnostics are required, route them through
the project logger at debug level without exposing wallet addresses or sensitive
error details.
- Line 21: Update the InfoIcon import in VerifyResult.tsx to use the shorter
relative path ../../icons/info, matching the surrounding imports and resolving
to the same module.
- Around line 172-185: The error handling in the gasless verification flow
incorrectly classifies all non-network failures as invalid paymaster addresses.
Update the relevant verification function and distinguish failures from the
token ownerOf read versus the paymaster whitelist/authorizedCallers read,
assigning an error message that reflects the failed step while preserving
network-error handling.
In `@src/gasless/buildSmartAccountClient.ts`:
- Around line 59-77: Update the paymaster configuration in
buildSmartAccountClient, specifically getPaymasterStubData and getPaymasterData,
to obtain paymasterData and gas limits from the configured paymaster source or
service instead of returning hardcoded empty data and magic-number limits.
Ensure both methods use the same authoritative values while preserving isFinal
on the stub response.
In `@src/gasless/checkDelegation.ts`:
- Around line 12-30: Bound the RPC request in the delegation check so an
unresponsive endpoint cannot leave send() stuck indefinitely. Update the
checkDelegation flow around the raw fetch to apply the project’s established
request-timeout approach, while preserving the existing false-on-error behavior;
preferably reuse the viem createPublicClient/getCode pattern already used by
checkPaymasterWhitelist.ts for consistent transport handling.
In `@src/gasless/gaslessHooks.test.tsx`:
- Around line 763-775: Strengthen the “state transitions” test for
useGaslessTransferHolder by making the mocked transaction confirmation deferred,
then assert INITIALIZED before sending and PENDING_CONFIRMATION after send
begins but before the deferred transaction resolves. Resolve the deferred
transaction and retain the final CONFIRMED assertion after the send completes.
- Around line 976-1028: Replace the three redundant tests in the describe block
with one gasless-path test that configures a sentinel VITE_PAYMASTER_ADDRESS,
stores a different paymaster in localStorage, and asserts
checkPaymasterWhitelist receives the localStorage value as
resolvedPaymasterAddress. Reuse the existing gasless setup and assertion pattern
near the earlier checkPaymasterWhitelist test, and remove the state-only
fallback tests.
- Around line 74-80: Move the ACCOUNT test value into a vi.hoisted declaration
alongside the other hoisted values, and use that hoisted symbol in the
useProviderContext mock factory and affected test setup. Remove the later const
ACCOUNT declaration while preserving the existing account value and mock
behavior.
In `@src/gasless/useGaslessNominate.ts`:
- Around line 106-117: Replace the inline structural cast on smartAccountClient
in the nominateGasless call with a shared client interface defined in the
gasless module. Update nominateGasless and related hooks to reuse that
interface, ensuring the sendTransaction signature remains checked consistently
and future contract drift is exposed by TypeScript.
In `@src/gasless/useGaslessRejectTransferHolder.ts`:
- Around line 77-106: Reuse the existing rpcUrl variable from the gasless
configuration flow when calling buildSmartAccountClient, instead of invoking
getRpcUrl(chainId!) again and reapplying a non-null assertion. Hoist or scope
rpcUrl so it remains available after the hasGaslessConfig checks while
preserving the existing validation that prevents the gasless path without a
valid RPC URL.
In `@src/gasless/useGaslessTransferHolder.ts`:
- Around line 153-154: Remove the unnecessary exhaustive-deps suppression in the
hook containing reset, and include the stable reset callback in that effect’s
dependency array. Keep the dependency behavior consistent with the surrounding
hooks, avoiding inline setter duplication unless needed to eliminate the reset
call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1c2bdd05-815e-451a-aa26-0a13176f32bb
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (35)
.npmrce2e/fixtures/local/w3c/tr_accept_surrender.jsone2e/fixtures/local/w3c/tr_reject_surrender.jsone2e/helpers/actions.tse2e/playwright.config.tse2e/setup-contracts.cjse2e/tests/nominate.spec.tse2e/tests/reject-return-to-issuer.spec.tse2e/tests/transfer-and-reject-beneficiary.spec.tse2e/tests/transfer-and-reject-owners.spec.tspackage.jsonsrc/components/AssetManagementPanel/AssetManagementForm/FormVariants/ActionSelectionForm/ActionSelectionForm.tsxsrc/components/common/Icons/Icons.tsxsrc/components/common/Icons/index.tssrc/components/common/contexts/TokenInformationContext/TokenInformationContext.tsxsrc/components/home/VerifySection/VerifyResult.tsxsrc/gasless/buildSmartAccountClient.tssrc/gasless/checkDelegation.test.tssrc/gasless/checkDelegation.tssrc/gasless/checkPaymasterWhitelist.test.tssrc/gasless/checkPaymasterWhitelist.tssrc/gasless/gaslessHooks.test.tsxsrc/gasless/index.tssrc/gasless/useGaslessAcceptReturned.tssrc/gasless/useGaslessNominate.tssrc/gasless/useGaslessRejectReturned.tssrc/gasless/useGaslessRejectTransferBeneficiary.tssrc/gasless/useGaslessRejectTransferHolder.tssrc/gasless/useGaslessRejectTransferOwners.tssrc/gasless/useGaslessReturnToIssuer.tssrc/gasless/useGaslessTransferBeneficiary.tssrc/gasless/useGaslessTransferHolder.tssrc/gasless/useGaslessTransferOwners.tssrc/hooks/useContractFunctionHook.tsxsrc/index.css
💤 Files with no reviewable changes (5)
- e2e/tests/transfer-and-reject-owners.spec.ts
- e2e/setup-contracts.cjs
- e2e/tests/reject-return-to-issuer.spec.ts
- e2e/tests/transfer-and-reject-beneficiary.spec.ts
- e2e/tests/nominate.spec.ts
- Extract shared makeGaslessHook factory to eliminate ~90-line duplication across 10 hooks; each hook is now a ~20-line thin wrapper - Add paymasterStorage.ts helper with custom event for same-tab reactivity - Make ActionSelectionForm reactive to paymaster localStorage changes - Add try/catch around eligibility checks to fall back to paid path on RPC failure - Add tokenRegistryAddress + tokenId to hasGaslessConfig for AcceptReturned/RejectReturned - Fix blank error messages for unknown/gasless errors with Error.message fallback - Add aria-invalid, aria-describedby, role="alert" to paymaster address input - Merge duplicate .check-gasless-content-success-text CSS rules - Replace hard-coded pixel dimensions with fluid values in pay-on-behalf CSS - Replace gap shorthand with column-gap to preserve row-gap: 0px
Previously the component rendered errorMessage OR children — never both. After the error-fallback fix in makeGaslessHook (e.message for unknown errors), errorMessage became truthy for contract-level reverts, hiding address/context children that E2E tests depend on. Now children always render; errorMessage appends below when present, giving users both the context (current addresses) and the error detail.
Swap localStorage for a module-level Map so the paymaster address clears on every page load. Also drops the cross-tab 'storage' event listener in ActionSelectionForm since it is no longer relevant. TODO: restore localStorage persistence when the feature is ready.
* chore: e2e tests for txns * feat: gasless transactions * fix: add legacy-peer-deps to resolve permissionless/ox/viem conflict permissionless@0.3.7 declares peerOptional ox@^0.11.3 but viem@2.55.1 ships ox@0.14.30, which is out of range. trustvc@2.15.0-beta.2 requires both viem@^2.53.1 and permissionless@^0.3.6, so neither can be downgraded. legacy-peer-deps makes npm skip the conflicting optional peer check. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: regenerate package-lock.json with sentry and react-ga4 entries Lock file was missing @sentry/react, @sentry/vite-plugin, and react-ga4 that were added during the upstream merge, causing npm ci to fail in CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: move whitelist fallback tests into gasless section for CI compatibility The two whitelist-fallback tests require hasGaslessConfig=true (PIMLICO_API_KEY set) to reach the whitelist check. In CI without a .env file the module-level constant is undefined, so the hook skips delegation/whitelist entirely and the assertions on checkPaymasterWhitelist always failed. Moving them into the gasless section which uses vi.stubEnv + vi.resetModules + dynamic imports ensures PIMLICO_API_KEY is set when these tests run. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add @playwright/test explicitly to ensure playwright-core is installed synpress-cache imports playwright-core at runtime. Since @playwright/test was only a transitive peer dep of synpress (not listed directly), it was not installed under legacy-peer-deps, causing ERR_MODULE_NOT_FOUND in CI during the e2e:setup-wallet step. Pinning to 1.48.2 matches the version already resolved in the lock file. * fix: exclude amoy-verify and pol-verify specs from main e2e run The pattern /verify-.*\.spec\.ts/ only matched files starting with "verify-", leaving amoy-verify.spec.ts and pol-verify.spec.ts in the main MetaMask suite. Those specs hit external RPC endpoints (Amoy/Polygon mainnet) which are unreliable in CI and have no MetaMask dependency. Widened to /.*verify.*\.spec\.ts/ so all verify specs (local, amoy, pol) run only via playwright.verify.config.ts. * chore: remove push trigger from e2e workflow E2E runs on every push to main/develop were expensive and unnecessary. Keeping only pull_request (gates PRs) and workflow_dispatch (manual runs). * fix: move @testing-library/dom to devDeps; disable e2e retries on dirty chain - @testing-library/dom belongs in devDependencies (test-only, not shipped) - retries disabled in playwright.config.ts: every spec mutates Hardhat chain state (transfer/reject/return), so a retry after partial failure hits an already-modified chain and fails for a different reason — retries here give false signal, not recovery Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: apply CodeRabbit review fixes for gasless transaction feature - Extract shared makeGaslessHook factory to eliminate ~90-line duplication across 10 hooks; each hook is now a ~20-line thin wrapper - Add paymasterStorage.ts helper with custom event for same-tab reactivity - Make ActionSelectionForm reactive to paymaster localStorage changes - Add try/catch around eligibility checks to fall back to paid path on RPC failure - Add tokenRegistryAddress + tokenId to hasGaslessConfig for AcceptReturned/RejectReturned - Fix blank error messages for unknown/gasless errors with Error.message fallback - Add aria-invalid, aria-describedby, role="alert" to paymaster address input - Merge duplicate .check-gasless-content-success-text CSS rules - Replace hard-coded pixel dimensions with fluid values in pay-on-behalf CSS - Replace gap shorthand with column-gap to preserve row-gap: 0px * fix: show both children and errorMessage in DocumentTransferMessage Previously the component rendered errorMessage OR children — never both. After the error-fallback fix in makeGaslessHook (e.message for unknown errors), errorMessage became truthy for contract-level reverts, hiding address/context children that E2E tests depend on. Now children always render; errorMessage appends below when present, giving users both the context (current addresses) and the error detail. * chore: reset paymaster address on page reload (in-memory store) Swap localStorage for a module-level Map so the paymaster address clears on every page load. Also drops the cross-tab 'storage' event listener in ActionSelectionForm since it is no longer relevant. TODO: restore localStorage persistence when the feature is ready. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: gasless transactions (#89) * chore: e2e tests for txns * feat: gasless transactions * fix: add legacy-peer-deps to resolve permissionless/ox/viem conflict permissionless@0.3.7 declares peerOptional ox@^0.11.3 but viem@2.55.1 ships ox@0.14.30, which is out of range. trustvc@2.15.0-beta.2 requires both viem@^2.53.1 and permissionless@^0.3.6, so neither can be downgraded. legacy-peer-deps makes npm skip the conflicting optional peer check. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: regenerate package-lock.json with sentry and react-ga4 entries Lock file was missing @sentry/react, @sentry/vite-plugin, and react-ga4 that were added during the upstream merge, causing npm ci to fail in CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: move whitelist fallback tests into gasless section for CI compatibility The two whitelist-fallback tests require hasGaslessConfig=true (PIMLICO_API_KEY set) to reach the whitelist check. In CI without a .env file the module-level constant is undefined, so the hook skips delegation/whitelist entirely and the assertions on checkPaymasterWhitelist always failed. Moving them into the gasless section which uses vi.stubEnv + vi.resetModules + dynamic imports ensures PIMLICO_API_KEY is set when these tests run. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add @playwright/test explicitly to ensure playwright-core is installed synpress-cache imports playwright-core at runtime. Since @playwright/test was only a transitive peer dep of synpress (not listed directly), it was not installed under legacy-peer-deps, causing ERR_MODULE_NOT_FOUND in CI during the e2e:setup-wallet step. Pinning to 1.48.2 matches the version already resolved in the lock file. * fix: exclude amoy-verify and pol-verify specs from main e2e run The pattern /verify-.*\.spec\.ts/ only matched files starting with "verify-", leaving amoy-verify.spec.ts and pol-verify.spec.ts in the main MetaMask suite. Those specs hit external RPC endpoints (Amoy/Polygon mainnet) which are unreliable in CI and have no MetaMask dependency. Widened to /.*verify.*\.spec\.ts/ so all verify specs (local, amoy, pol) run only via playwright.verify.config.ts. * chore: remove push trigger from e2e workflow E2E runs on every push to main/develop were expensive and unnecessary. Keeping only pull_request (gates PRs) and workflow_dispatch (manual runs). * fix: move @testing-library/dom to devDeps; disable e2e retries on dirty chain - @testing-library/dom belongs in devDependencies (test-only, not shipped) - retries disabled in playwright.config.ts: every spec mutates Hardhat chain state (transfer/reject/return), so a retry after partial failure hits an already-modified chain and fails for a different reason — retries here give false signal, not recovery Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: apply CodeRabbit review fixes for gasless transaction feature - Extract shared makeGaslessHook factory to eliminate ~90-line duplication across 10 hooks; each hook is now a ~20-line thin wrapper - Add paymasterStorage.ts helper with custom event for same-tab reactivity - Make ActionSelectionForm reactive to paymaster localStorage changes - Add try/catch around eligibility checks to fall back to paid path on RPC failure - Add tokenRegistryAddress + tokenId to hasGaslessConfig for AcceptReturned/RejectReturned - Fix blank error messages for unknown/gasless errors with Error.message fallback - Add aria-invalid, aria-describedby, role="alert" to paymaster address input - Merge duplicate .check-gasless-content-success-text CSS rules - Replace hard-coded pixel dimensions with fluid values in pay-on-behalf CSS - Replace gap shorthand with column-gap to preserve row-gap: 0px * fix: show both children and errorMessage in DocumentTransferMessage Previously the component rendered errorMessage OR children — never both. After the error-fallback fix in makeGaslessHook (e.message for unknown errors), errorMessage became truthy for contract-level reverts, hiding address/context children that E2E tests depend on. Now children always render; errorMessage appends below when present, giving users both the context (current addresses) and the error detail. * chore: reset paymaster address on page reload (in-memory store) Swap localStorage for a module-level Map so the paymaster address clears on every page load. Also drops the cross-tab 'storage' event listener in ActionSelectionForm since it is no longer relevant. TODO: restore localStorage persistence when the feature is ready. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: apply CodeRabbit review fixes (round 2) (#94) * fix: apply CodeRabbit review fixes (round 2) - Icons: use stroke prop for line/circle in warning icon (was hardcoded #FF8200) - VerifyResult: remove debug console statements leaking RPC URL and wallet identifiers - checkDelegation: add 10s AbortController timeout to RPC fetch - AcceptReturned/RejectReturned: add tokenId validation to directGuard - useContactForm: validate presigned.length === pendingItems.length before upload - index.css: replace fixed height/width on gasless error classes with min-height/auto * chore: pin @trustvc/trustvc to exact version 2.15.0-beta.2 Remove caret range to prevent unintended upgrades to future beta versions. * fix: merge conflicts (#98) * fix: code rabbit changes * chore: replace legacy-peer-deps with targeted ox override for permissionless permissionless@0.3.7 has optional peer ox@^0.11.3 but viem@2.55.1 ships ox@0.14.30, which is outside that range. Adding overrides.permissionless.ox in package.json pins the resolution to 0.14.30 so npm resolves cleanly without the blanket legacy-peer-deps flag. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: code rabit comments --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: wire VITE_PIMLICO_API_KEY into dev and prod deploy workflows (#99) Without this key at build time hasGaslessConfig evaluates to false in makeGaslessHook, causing every transaction to fall back to the direct (payable) path even after paymaster verification succeeds. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
src/gasless/) that lets EIP-7702 delegated accounts submit token-registry transactions fee-free via a platform paymaster. Covers all 10 transaction types: Transfer Holder/Beneficiary/Owners, Reject Transfer Holder/Beneficiary/Owners, Return to Issuer, Accept Return to Issuer, Reject Return to Issuer, and Nominate Beneficiary.dismissMetaMaskPopups, MetaMask unlock helpers, screen recording via ffmpeg, longer CI timeouts, and additional fixture tokens for nominate/OA/W3C verification flows.checkEIP7702Delegation,checkPaymasterWhitelist, and all 10 gasless hooks (52 tests covering gasless path, fallback path, error handling, reset, and paymaster localStorage).Changes
New:
src/gasless/checkDelegation.ts— checkseth_getCodefor the0xef0100EIP-7702 prefixcheckPaymasterWhitelist.ts— readsauthorizedCallers+authorizedTitleEscrowsfrom the platform paymaster contract in parallelbuildSmartAccountClient.ts— builds a Pimlico/permissionless smart account client from the user's EOAuseGaslessTransferHolder.ts+ 9 sibling hooks — each hook checks delegation → checks whitelist → takes gasless or paid fallback pathindex.ts— re-exports all hooks*.test.ts,gaslessHooks.test.tsx)Modified:
src/components/home/VerifySection/VerifyResult.tsxdata-testidattributes required by e2e specsE2E (
e2e/)setup-contracts.cjs— correctedADDRESS_EXAMPLE_2, addednominateToken, added OA/W3C verification token mint entrieshelpers/actions.ts— addeddismissMetaMaskPopups, MetaMask unlock inconnectMetaMask/switchMetaMaskAccount,hardhatRpc,hardhatRpcNode,revokeMetamaskPermissionsplaywright.config.ts— addedtestIgnorefor verify specs,retain-on-failuretrace/video,slowMo: 800.github/workflows/e2e.yml— 60-min job timeout, 180s node/server waits, ffmpeg screen recording, full dev server env varsTest plan
npm test— all unit tests pass (52 gasless hook tests + delegation + whitelist tests)npm run e2e— all 10 happy-path transaction specs pass locally against Hardhatreset()clears state correctlySummary by CodeRabbit
New Features
Bug Fixes
Tests
Chores