Skip to content

feat: clone-based paymaster factory with initialize pattern#1

Open
RishabhS7 wants to merge 7 commits into
mainfrom
dev
Open

feat: clone-based paymaster factory with initialize pattern#1
RishabhS7 wants to merge 7 commits into
mainfrom
dev

Conversation

@RishabhS7

@RishabhS7 RishabhS7 commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator
  • PlatformPaymaster: single-param constructor (entryPoint only); initialize() sets owner/dailyLimit/tdocDeployer on clones
  • Factory: Clones.cloneDeterministic; stores paymasterImplementation + tdocDeployer; onlyOwner update functions
  • Mocks: MockEntryPoint, MockRegistry, MockTdocDeployer for unit tests
  • Tests: 18 Factory + 27 PlatformPaymaster tests, all passing
  • Scripts: deployImplementation, deployFactory, updated deployPlatformPaymaster
  • src/abis: generated ABI exports for npm package (@trustvc/eip7702)
  • Remove: interactionContrats, Lock.sol, Lock.ts, 7702Frontend and dist added to gitignore noreply@anthropic.com>

Summary by CodeRabbit

  • New Features
    • Added reusable CI workflows for linting, tests, and commit message checks, plus ESLint review annotations.
    • Added automated releases on pushes to main and dev.
    • Updated the contracts for deterministic paymaster cloning and a new PlatformPaymaster initialization/authorization flow.
    • Added generated ABI/type exports and SDK entrypoints, plus deployment/ABI generation scripts.
  • Tests
    • Added test coverage for the factory and PlatformPaymaster, including supporting mock contracts.
  • Chores
    • Improved lint/build tooling and package manifest/outputs.
  • Breaking Changes
    • Removed the 7702Frontend app and multiple legacy interaction/Etherspot contract components.

- PlatformPaymaster: single-param constructor (entryPoint only); initialize() sets owner/dailyLimit/tdocDeployer on clones
- Factory: Clones.cloneDeterministic; stores paymasterImplementation + tdocDeployer; onlyOwner update functions
- Mocks: MockEntryPoint, MockRegistry, MockTdocDeployer for unit tests
- Tests: 18 Factory + 27 PlatformPaymaster tests, all passing
- Scripts: deployImplementation, deployFactory, updated deployPlatformPaymaster
- src/abis: generated ABI exports for npm package (@trustvc/eip7702)
- Remove: interactionContrats, Lock.sol, Lock.ts, 7702Frontend and dist added to gitignore
noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR updates the factory and paymaster contracts for clone-based deployment and initializer wiring, adds generated ABI/package tooling and deployment scripts, and adds CI/lint workflows while removing the 7702Frontend app and legacy Solidity sources.

Changes

Contract refactor and test coverage

Layer / File(s) Summary
Factory clone deployment
contracts/Factory.sol
PlatformAccountFactory now stores configurable deployer and implementation addresses, deploys deterministic clones, and predicts clone addresses from the implementation, salt, and factory address.
Paymaster initializer and authorization
contracts/PlatformPaymaster.sol
PlatformPaymaster adds initializer-based setup, authorizedCallers and documentsMinted state, caller/title-escrow admin methods, updated mintDocument side effects, and revised paymaster validation rules.
Mocks and contract tests
contracts/mocks/MockEntryPoint.sol, contracts/mocks/MockRegistry.sol, contracts/mocks/MockTdocDeployer.sol, test/Factory.ts, test/PlatformPaymaster.ts
Mock entry point, registry, and TDoc deployer contracts are added, and the factory/paymaster test suites cover initialization, updates, clone deployment, authorization toggles, registry deployment, minting, and spend queries.

Package tooling, scripts, and generated exports

Layer / File(s) Summary
Generated ABIs and package entry points
src/abis/..., src/constants/index.ts, src/index.ts, scripts/generate-abis.ts
Generated ABI constants and types are added, src/constants/index.ts adds chain and contract addresses, src/index.ts re-exports namespaces, and scripts/generate-abis.ts generates the ABI modules from artifacts.
Build and publish configuration
tsup.config.ts, tsconfig.build.json, package.json
Build configuration, package exports, scripts, and dependency layout are added for publishing.
Deployment scripts
scripts/deployImplementation.ts, scripts/deployFactory.ts, scripts/deployPlatformPaymaster.ts, scripts/deployEIP7702.ts, scripts/deployRegistryGasless.ts, scripts/mintDocumentGasless.ts, scripts/stakePlatformPaymaster.ts, scripts/trFunctions/*
Network-aware deployment and transaction scripts are added or updated for implementation, factory, paymaster, registry, gasless minting, staking, and TR actions.

CI, linting, and repository cleanup

Layer / File(s) Summary
Workflows and lint configuration
.github/workflows/*, .eslintrc.json, .eslintignore, commitlint.config.js, .gitignore
GitHub Actions workflows and linting configuration are added or updated, including PR, release, tests, and linters workflows.
Frontend and legacy Solidity removals
7702Frontend/..., interactionContrats/..., contracts/Lock.sol, test/Lock.ts, ignition/modules/Lock.ts, scripts/stakeOwnerOnEP9.ts, README.md
The frontend app and legacy Solidity files are removed, along with the Lock contract, its test, Ignition module, and staking script; the README is replaced with project documentation.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐇 Hop, hop—clones now bloom from one small seed,
ABIs and scripts keep pace with every need.
The lint brooms sweep, the workflows hum along,
And old app burrows fade where docs sing strong.
With paymaster guards and tests in tidy rows,
This rabbit leaves a trail of careful glows.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: a clone-based paymaster factory using an initialize pattern.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 17

🧹 Nitpick comments (5)
.github/workflows/release.yml (1)

34-40: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Cache the npm cache, not ~/node_modules.

npm ci installs into the workspace node_modules and deletes it on each run, so the current cache never warms this job. Switching actions/setup-node to cache: npm (or caching ~/.npm) will make the release pipeline faster and more predictable.

Also applies to: 47-52

🤖 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 @.github/workflows/release.yml around lines 34 - 40, The current cache step
is targeting ~/node_modules, but npm ci recreates workspace node_modules on
every run so this cache will not be reused effectively. Update the release
workflow cache setup around the node module caching step to cache the npm
download cache instead, preferably by using actions/setup-node with cache: npm
or by caching ~/.npm, and make the same change in the other matching cache block
so both release jobs benefit consistently.
scripts/deployFactory.ts (2)

57-57: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add timeout to waitForTransactionReceipt.

Without a timeout, this call can hang indefinitely if the RPC drops the transaction or network partitions.

-  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
+  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash, timeout: 120_000 });
🤖 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 `@scripts/deployFactory.ts` at line 57, The `waitForTransactionReceipt` call in
`deployFactory.ts` can hang forever if the transaction is dropped or the network
stalls. Update the `publicClient.waitForTransactionReceipt` invocation to
include a timeout (and any related retry/confirmation options if available) so
the deployment flow fails fast instead of waiting indefinitely.

61-70: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding contract verification step.

After deployment, consider verifying the contract on Etherscan/Sourcify so the source is available for the factory address consumers will interact with.

#!/bin/bash
# Example: add to package.json scripts or CI
# npx hardhat verify --network sepolia <factoryAddress> <tdocDeployer> <paymasterImpl>
🤖 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 `@scripts/deployFactory.ts` around lines 61 - 70, Add a post-deployment
contract verification step to the deploy output in deployFactory.ts so users can
verify the factory contract on Etherscan/Sourcify after deployment. Update the
console guidance near the existing “Next steps” section and reference the
deployed factoryAddress along with the constructor args used by the deployment
flow (tdocDeployer and paymasterImpl), so consumers know how to run verification
for the PlatformAccountFactory.
scripts/deployPlatformPaymaster.ts (2)

31-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant FACTORY_ADDRESS validation.

The env var is checked at module level (lines 31-32) and again in main() (line 43). Since FACTORY_ADDRESS is a const evaluated at module load, the main() check is unreachable if the module-level check passes. Remove the duplicate or keep only the module-level check.

-  if (!FACTORY_ADDRESS) throw new Error("FACTORY_ADDRESS not set");
🤖 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 `@scripts/deployPlatformPaymaster.ts` around lines 31 - 43, The
`FACTORY_ADDRESS` check in `main()` is redundant because
`deployPlatformPaymaster.ts` already validates `process.env.FACTORY_ADDRESS` at
module load and assigns `FACTORY_ADDRESS` before `main()` runs. Remove the
duplicate guard inside `main()` (or move the validation there and eliminate the
top-level check) so the environment validation happens only once and stays
centered around the `FACTORY_ADDRESS` constant.

81-83: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add timeout to waitForTransactionReceipt.

Same concern as deployFactory.ts - this can hang indefinitely without a timeout.

   const receipt = await publicClient.waitForTransactionReceipt({
     hash: txHash,
+    timeout: 120_000,
   });
🤖 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 `@scripts/deployPlatformPaymaster.ts` around lines 81 - 83, The transaction
receipt wait in deployPlatformPaymaster can hang indefinitely because
publicClient.waitForTransactionReceipt is called without a timeout. Update the
receipt wait in the deployPlatformPaymaster flow to pass an explicit timeout
(consistent with deployFactory.ts) so the script fails fast instead of blocking
forever. Keep the change localized to the waitForTransactionReceipt call and
ensure the timeout value is clearly set there.
🤖 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 @.eslintrc.json:
- Around line 17-22: The ESLint config currently enables
import/no-extraneous-dependencies without registering the import plugin, which
causes lint config loading to fail. Update .eslintrc.json to either add the
eslint-plugin-import plugin configuration alongside the existing rules or remove
the import/no-extraneous-dependencies rule if the plugin is not intended to be
used. Make sure the fix is applied in the top-level ESLint config so npm run
lint can load successfully.

In @.github/workflows/linters.yml:
- Around line 25-28: The dependency installation in the linter workflow
currently uses npm install, which can drift from the pinned CI dependency set
and run scripts too early. Update the Install Commit Lint Dependencies step in
linters.yml to use npm ci with --ignore-scripts so it matches the lockfile-based
install used elsewhere and avoids lifecycle script execution while checkout
credentials are present.
- Around line 21-28: The Commit Lint job currently includes
JulienKode/pull-request-name-linter-action in the reusable linters workflow, but
that action only works on pull_request events and can break release runs
triggered from release.yml on push to main. Move the PR title check out of the
linters job in linters.yml into the pull_requests workflow, or add an event
guard on the existing step/job so it only runs when github.event_name is
pull_request.

In @.github/workflows/pull_requests.yml:
- Around line 2-3: The pull request workflow trigger is missing the edited
event, so PR-title validation will not rerun when only the title changes. Update
the pull_request.types configuration in the workflow definition to include
edited alongside opened, reopened, and synchronize so the linter stack
revalidates titles after edits.
- Around line 19-30: The eslint-review job only checks out the repository before
running reviewdog/action-eslint, so the local eslint binary and TypeScript
ESLint packages are missing. Update the workflow to add actions/setup-node and
run npm ci before the reviewdog step, using the eslint-review job as the place
to insert the dependency installation steps.

In `@contracts/Factory.sol`:
- Around line 16-21: The Factory configuration paths can currently accept
non-contract addresses, which later breaks clone deployment and
PlatformPaymaster initialization. Update the Factory constructor and the config
entry points around the existing _tdocDeployer and _paymasterImplementation
assignments to mirror the nonzero checks and also require that both addresses
contain contract code, using the existing validation flow in Factory and related
deploy/setup functions. Keep the checks consistent wherever these addresses are
set so invalid deployer or implementation values are rejected before any clone
or paymaster logic runs.
- Around line 36-48: The deterministic clone salt in deployPlatformPaymaster and
computePaymasterAddress is currently only `salt`, so any caller can reuse it for
a different platform. Update Factory to derive the clone salt from
`platformAddress` (or require platform authorization) and use the same derived
value in both `Clones.cloneDeterministic` and
`Clones.predictDeterministicAddress`, keeping the deployment and prediction
logic consistent.

In `@contracts/mocks/MockRegistry.sol`:
- Around line 17-24: The MockRegistry access-control stub is too permissive and
hides real failures in tests. Update the IAccessControl methods in MockRegistry
so grantRole and renounceRole behave like AccessControl: only the role admin can
grant a role, and renounceRole must only clear the role for the account passed
in and require that account to be msg.sender. Use the existing _roles storage in
MockRegistry to enforce these checks so mintDocument/registry tests fail when
PlatformPaymaster is configured with the wrong admin or principal.

In `@contracts/mocks/MockTdocDeployer.sol`:
- Around line 10-15: The MockTdocDeployer.deploy mock is ignoring the forwarded
implementation address, so it cannot catch bad values passed across the
paymaster → deployer boundary. Update deploy() to accept and use the
implementation argument when constructing the deployed registry path, and keep
MockRegistry creation aligned with the forwarded implementation plus the decoded
admin from params. This will ensure deployRegistry failures from address(0) or
stale implementations surface in the test suite.

In `@contracts/PlatformPaymaster.sol`:
- Around line 256-260: Update PlatformPaymaster validation so mint sponsorship
is checked the same way as other protected calls: in the validation path around
the mintDocument handling, reuse the same authorizedCallers/owner authorization
and dailyLimit/dailySpend logic currently used before sponsor approval. If the
sender is not authorized or the projected spend would exceed the limit, emit the
same rejection event and return a failed validation result instead of accepting
the UserOp for execution.
- Around line 95-104: The PlatformPaymaster.initialize function only validates
_owner, so an invalid _tdocDeployer can be permanently stored and break
deployRegistry with no recovery path. Add an initializer guard in initialize to
reject a zero address and any address that is not a contract before assigning
tdocDeployer, keeping the existing ownership and dailyLimit setup intact.
- Around line 171-185: Add a caller authorization check before the mint flow in
mintDocument so only approved requesters can use the paymaster to mint;
currently the code only validates authorizedRegistries[registry] and then
proceeds to mint and auto-authorize beneficiary and holder. Update the
mintDocument logic in PlatformPaymaster to gate access with an appropriate
authorization mapping or role check before calling
ITradeTrustToken(registry).mint, while keeping the existing registry validation
and post-mint authorization updates for titleEscrow, authorizedCallers,
authorizedTitleEscrows, and documentsMinted.

In `@package.json`:
- Around line 32-41: The npm scripts in package.json are using POSIX-only shell
syntax, which breaks on Windows. Update the build:sol, build:abis, and test
scripts to set TS_NODE_TRANSPILE_ONLY via a cross-platform mechanism such as
cross-env, and replace the clean script’s rm -rf with a cross-platform delete
approach like rimraf or a Node-based cleanup helper. Keep the existing script
names and wiring in place so build, test, and clean continue to work
consistently across shells.

In `@scripts/deployFactory.ts`:
- Around line 31-33: The PRIVATE_KEY handling in deployFactory should be
consistent with the trimmed account/env inputs used elsewhere. Trim the
process.env.PRIVATE_KEY value before passing it into privateKeyToAccount in the
deployer setup, and make sure the deployer initialization path uses the
sanitized string rather than the raw env var so whitespace does not break
account creation.

In `@scripts/deployImplementation.ts`:
- Around line 21-29: The deployment flow is using a default EntryPoint in
`deployImplementation` that can diverge from the one used by
`stakePlatformPaymaster`, causing the paymaster to be deployed/staked against
different EntryPoints. Centralize the EntryPoint selection in a shared constant
or config used by both scripts, or require `ENTRY_POINT` explicitly in both
`main` functions so `DEFAULT_ENTRY_POINT` cannot silently drift from the
paymaster staking path.

In `@scripts/generate-abis.ts`:
- Around line 47-60: The main flow in main() deletes OUT_DIR before verifying
all CONTRACTS_TO_EXPORT artifacts exist, which can leave src/index.ts pointing
at a missing ./abis folder if validation fails. Move the artifact existence
checks for each artifactPath ahead of the fs.rmSync/fs.mkdirSync cleanup, or
generate into a temporary directory and only replace OUT_DIR after all artifacts
are confirmed and generation succeeds. Use main, CONTRACTS_TO_EXPORT, OUT_DIR,
and artifactPath to locate the fix.

In `@test/PlatformPaymaster.ts`:
- Around line 285-339: The mintDocument tests only verify mapping updates and
event side effects, so add coverage for the actual sponsorship gate in
_validatePaymasterUserOp. Extend the existing mintDocument suite in
PlatformPaymaster to assert that a user and holder authorized by mintDocument
are accepted by the paymaster validation path, and that an unrelated caller is
still rejected. Use the existing paymaster, paymasterAsOther, authorizedCallers,
and _validatePaymasterUserOp flow so the test proves the new sponsorship check
works end to end.

---

Nitpick comments:
In @.github/workflows/release.yml:
- Around line 34-40: The current cache step is targeting ~/node_modules, but npm
ci recreates workspace node_modules on every run so this cache will not be
reused effectively. Update the release workflow cache setup around the node
module caching step to cache the npm download cache instead, preferably by using
actions/setup-node with cache: npm or by caching ~/.npm, and make the same
change in the other matching cache block so both release jobs benefit
consistently.

In `@scripts/deployFactory.ts`:
- Line 57: The `waitForTransactionReceipt` call in `deployFactory.ts` can hang
forever if the transaction is dropped or the network stalls. Update the
`publicClient.waitForTransactionReceipt` invocation to include a timeout (and
any related retry/confirmation options if available) so the deployment flow
fails fast instead of waiting indefinitely.
- Around line 61-70: Add a post-deployment contract verification step to the
deploy output in deployFactory.ts so users can verify the factory contract on
Etherscan/Sourcify after deployment. Update the console guidance near the
existing “Next steps” section and reference the deployed factoryAddress along
with the constructor args used by the deployment flow (tdocDeployer and
paymasterImpl), so consumers know how to run verification for the
PlatformAccountFactory.

In `@scripts/deployPlatformPaymaster.ts`:
- Around line 31-43: The `FACTORY_ADDRESS` check in `main()` is redundant
because `deployPlatformPaymaster.ts` already validates
`process.env.FACTORY_ADDRESS` at module load and assigns `FACTORY_ADDRESS`
before `main()` runs. Remove the duplicate guard inside `main()` (or move the
validation there and eliminate the top-level check) so the environment
validation happens only once and stays centered around the `FACTORY_ADDRESS`
constant.
- Around line 81-83: The transaction receipt wait in deployPlatformPaymaster can
hang indefinitely because publicClient.waitForTransactionReceipt is called
without a timeout. Update the receipt wait in the deployPlatformPaymaster flow
to pass an explicit timeout (consistent with deployFactory.ts) so the script
fails fast instead of blocking forever. Keep the change localized to the
waitForTransactionReceipt call and ensure the timeout value is clearly set
there.
🪄 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

Run ID: 348a6507-544f-4435-86d6-d623b7aad175

📥 Commits

Reviewing files that changed from the base of the PR and between 8f1de74 and aff13bb.

⛔ Files ignored due to path filters (2)
  • 7702Frontend/package-lock.json is excluded by !**/package-lock.json
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (70)
  • .eslintignore
  • .eslintrc.json
  • .github/workflows/linters.yml
  • .github/workflows/pull_requests.yml
  • .github/workflows/release.yml
  • .github/workflows/tests.yml
  • .gitignore
  • 7702Frontend/.env.example
  • 7702Frontend/index.html
  • 7702Frontend/package.json
  • 7702Frontend/postcss.config.js
  • 7702Frontend/src/App.tsx
  • 7702Frontend/src/components/DelegationPanel.tsx
  • 7702Frontend/src/components/PaymasterAdminPanel.tsx
  • 7702Frontend/src/components/PaymasterPanel.tsx
  • 7702Frontend/src/components/RegistryPanel.tsx
  • 7702Frontend/src/components/SignerPanel.tsx
  • 7702Frontend/src/components/StoragePanel.tsx
  • 7702Frontend/src/components/TitleEscrowPanel.tsx
  • 7702Frontend/src/components/TrustVCPanel.tsx
  • 7702Frontend/src/components/WalletConnect.tsx
  • 7702Frontend/src/index.css
  • 7702Frontend/src/lib/abis.ts
  • 7702Frontend/src/lib/constants.ts
  • 7702Frontend/src/lib/pimlico.ts
  • 7702Frontend/src/main.tsx
  • 7702Frontend/src/vite-env.d.ts
  • 7702Frontend/tailwind.config.js
  • 7702Frontend/tsconfig.json
  • 7702Frontend/vite.config.ts
  • commitlint.config.js
  • contracts/Factory.sol
  • contracts/Lock.sol
  • contracts/PlatformPaymaster.sol
  • contracts/mocks/MockEntryPoint.sol
  • contracts/mocks/MockRegistry.sol
  • contracts/mocks/MockTdocDeployer.sol
  • ignition/modules/Lock.ts
  • interactionContrats/TitleEscrow.sol
  • interactionContrats/TitleEscrowFactory.sol
  • interactionContrats/TradeTrustToken.sol
  • interactionContrats/base/RegistryAccess.sol
  • interactionContrats/base/SBTUpgradeable.sol
  • interactionContrats/base/TradeTrustSBT.sol
  • interactionContrats/base/TradeTrustTokenBase.sol
  • interactionContrats/base/TradeTrustTokenBaseURI.sol
  • interactionContrats/base/TradeTrustTokenBurnable.sol
  • interactionContrats/base/TradeTrustTokenMintable.sol
  • interactionContrats/base/TradeTrustTokenRestorable.sol
  • interactionContrats/utils/SigHelper.sol
  • interactionContrats/utils/TDocDeployer.sol
  • package.json
  • scripts/deployFactory.ts
  • scripts/deployImplementation.ts
  • scripts/deployPlatformPaymaster.ts
  • scripts/generate-abis.ts
  • scripts/mintDocumentGasless.ts
  • scripts/stakeOwnerOnEP9.ts
  • src/abis/eip7702-implementation.ts
  • src/abis/index.ts
  • src/abis/platform-account-factory.ts
  • src/abis/platform-paymaster.ts
  • src/constants/index.ts
  • src/index.ts
  • test/Factory.ts
  • test/Lock.ts
  • test/PlatformPaymaster.ts
  • tsconfig.build.json
  • tsup.config.ts
  • upload.json
💤 Files with no reviewable changes (40)
  • 7702Frontend/tailwind.config.js
  • 7702Frontend/package.json
  • interactionContrats/base/RegistryAccess.sol
  • interactionContrats/base/TradeTrustTokenMintable.sol
  • interactionContrats/base/TradeTrustTokenBaseURI.sol
  • 7702Frontend/tsconfig.json
  • ignition/modules/Lock.ts
  • contracts/Lock.sol
  • interactionContrats/base/TradeTrustTokenBase.sol
  • interactionContrats/base/TradeTrustTokenBurnable.sol
  • interactionContrats/utils/SigHelper.sol
  • 7702Frontend/src/lib/pimlico.ts
  • interactionContrats/base/SBTUpgradeable.sol
  • interactionContrats/TradeTrustToken.sol
  • 7702Frontend/src/components/DelegationPanel.tsx
  • 7702Frontend/index.html
  • 7702Frontend/src/vite-env.d.ts
  • 7702Frontend/postcss.config.js
  • 7702Frontend/src/components/TrustVCPanel.tsx
  • 7702Frontend/vite.config.ts
  • interactionContrats/TitleEscrowFactory.sol
  • 7702Frontend/src/index.css
  • 7702Frontend/src/App.tsx
  • 7702Frontend/src/components/SignerPanel.tsx
  • test/Lock.ts
  • 7702Frontend/src/lib/abis.ts
  • scripts/stakeOwnerOnEP9.ts
  • 7702Frontend/src/components/TitleEscrowPanel.tsx
  • 7702Frontend/src/lib/constants.ts
  • 7702Frontend/src/components/PaymasterPanel.tsx
  • interactionContrats/utils/TDocDeployer.sol
  • 7702Frontend/src/components/PaymasterAdminPanel.tsx
  • 7702Frontend/src/main.tsx
  • interactionContrats/base/TradeTrustTokenRestorable.sol
  • 7702Frontend/src/components/StoragePanel.tsx
  • 7702Frontend/src/components/WalletConnect.tsx
  • 7702Frontend/.env.example
  • interactionContrats/base/TradeTrustSBT.sol
  • interactionContrats/TitleEscrow.sol
  • 7702Frontend/src/components/RegistryPanel.tsx

Comment thread .eslintrc.json
Comment on lines +17 to +22
"rules": {
"no-console": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"import/no-extraneous-dependencies": "off"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files of interest:\n'
git ls-files .eslintrc.json package.json .github/workflows/linters.yml

printf '\n--- .eslintrc.json ---\n'
cat -n .eslintrc.json

printf '\n--- package.json (relevant lines) ---\n'
cat -n package.json | sed -n '1,220p'

printf '\n--- workflow excerpt ---\n'
cat -n .github/workflows/linters.yml | sed -n '1,220p'

printf '\n--- search for import plugin / extends ---\n'
rg -n '"eslint-plugin-import"|"\bimport/no-extraneous-dependencies\b"|extends|plugins' .eslintrc.json package.json .github/workflows/linters.yml

Repository: TrustVC/7702SmartAccount

Length of output: 5812


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf 'noop\n'

Repository: TrustVC/7702SmartAccount

Length of output: 167


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "ROOT=$(pwd)"
echo "--- .eslintrc.json ---"
cat -n .eslintrc.json
echo "--- package.json plugin/import search ---"
rg -n '"eslint-plugin-import"|"import/no-extraneous-dependencies"|extends|plugins' package.json .eslintrc.json

Repository: TrustVC/7702SmartAccount

Length of output: 1859


Add eslint-plugin-import or remove this rule. .eslintrc.json:8-22 references import/no-extraneous-dependencies without registering the import plugin, so npm run lint fails on config load.

🤖 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 @.eslintrc.json around lines 17 - 22, The ESLint config currently enables
import/no-extraneous-dependencies without registering the import plugin, which
causes lint config loading to fail. Update .eslintrc.json to either add the
eslint-plugin-import plugin configuration alongside the existing rules or remove
the import/no-extraneous-dependencies rule if the plugin is not intended to be
used. Make sure the fix is applied in the top-level ESLint config so npm run
lint can load successfully.

Comment on lines +21 to +28
commit-lint:
name: Commit Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Commit Lint Dependencies
run: npm install @commitlint/config-conventional
- uses: JulienKode/pull-request-name-linter-action@v0.5.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== workflows files ==\n'
git ls-files .github/workflows

printf '\n== linters.yml (numbered) ==\n'
cat -n .github/workflows/linters.yml

printf '\n== release.yml (numbered) ==\n'
cat -n .github/workflows/release.yml

Repository: TrustVC/7702SmartAccount

Length of output: 2824


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== lines mentioning workflow_call / pull_request / push ==\n'
rg -n "workflow_call|pull_request|push|pull_request_target|workflow_dispatch|commit-lint|pull-request-name-linter-action|npm install `@commitlint/config-conventional`" .github/workflows

Repository: TrustVC/7702SmartAccount

Length of output: 647


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
for path in [Path('.github/workflows/linters.yml'), Path('.github/workflows/release.yml')]:
    print(f"\n== {path} ==")
    text = path.read_text()
    for i, line in enumerate(text.splitlines(), 1):
        if 'commit-lint' in line or 'pull-request-name-linter-action' in line or 'workflow_call' in line or 'pull_request' in line or 'push:' in line or 'main' in line:
            print(f"{i:4}: {line}")
PY

Repository: TrustVC/7702SmartAccount

Length of output: 383


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== pull_requests.yml (numbered) ==\n'
cat -n .github/workflows/pull_requests.yml

printf '\n== references to pull-request-name-linter-action across repo ==\n'
rg -n "pull-request-name-linter-action|commit-lint|Commit Lint|pr title|pull request name" .

Repository: TrustVC/7702SmartAccount

Length of output: 1063


🌐 Web query:

JulienKode/pull-request-name-linter-action requires pull_request event title github context

💡 Result:

The JulienKode/pull-request-name-linter-action specifically requires a pull_request event to function because it relies on the GitHub Actions context to retrieve the pull request title [1]. The action retrieves the title internally from the GitHub context payload using github.context.payload.pull_request.title [1]. Because of this, it must be triggered by a workflow configured with the pull_request event [2][3]. To ensure the action correctly receives the pull request title, your workflow must include the appropriate configuration in the on: section [2][3]: on: pull_request: types: ['opened', 'edited', 'reopened', 'synchronize'] If a workflow is triggered by an event that does not contain pull request metadata (such as a push event), the action will not have access to the title [4][5]. Furthermore, users have noted that if you manually re-run a workflow, the action may use the cached title from the original event payload rather than the updated PR title [6]. If you find the action is not detecting title changes, ensure that your workflow includes the edited activity type [2][7].

Citations:


Move the PR-title lint out of the reusable workflow. JulienKode/pull-request-name-linter-action only works on pull_request events, but .github/workflows/release.yml reuses linters.yml on push to main, so this job can fail in release runs. Move it to .github/workflows/pull_requests.yml or guard it with if: github.event_name == 'pull_request'.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 25-25: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 27-27: ad-hoc installation of packages (adhoc-packages): installs a package outside of a lockfile

(adhoc-packages)

🤖 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 @.github/workflows/linters.yml around lines 21 - 28, The Commit Lint job
currently includes JulienKode/pull-request-name-linter-action in the reusable
linters workflow, but that action only works on pull_request events and can
break release runs triggered from release.yml on push to main. Move the PR title
check out of the linters job in linters.yml into the pull_requests workflow, or
add an event guard on the existing step/job so it only runs when
github.event_name is pull_request.

Comment thread .github/workflows/linters.yml
Comment on lines +2 to +3
pull_request:
types: [opened, reopened, synchronize]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Re-run this workflow when the PR title is edited.

The linter stack now includes PR-title validation, but pull_request.types excludes edited. A title fixed after a failure will not be revalidated until someone pushes another commit or reopens the PR.

Suggested fix
   pull_request:
-    types: [opened, reopened, synchronize]
+    types: [opened, reopened, synchronize, edited]
📝 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.

Suggested change
pull_request:
types: [opened, reopened, synchronize]
pull_request:
types: [opened, reopened, synchronize, edited]
🤖 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 @.github/workflows/pull_requests.yml around lines 2 - 3, The pull request
workflow trigger is missing the edited event, so PR-title validation will not
rerun when only the title changes. Update the pull_request.types configuration
in the workflow definition to include edited alongside opened, reopened, and
synchronize so the linter stack revalidates titles after edits.

Comment thread .github/workflows/pull_requests.yml
Comment thread package.json
Comment on lines +32 to +41
"build:sol": "TS_NODE_TRANSPILE_ONLY=1 hardhat compile",
"build:abis": "TS_NODE_TRANSPILE_ONLY=1 ts-node scripts/generate-abis.ts",
"build:js": "tsup",
"build": "npm run build:sol && npm run build:abis && npm run build:js",
"clean": "rm -rf dist cache artifacts src/abis",
"lint": "eslint src scripts test --ext .ts",
"lint:fix": "npm run lint -- --fix",
"prepublishOnly": "npm run build",
"semantic-release": "semantic-release",
"test": "TS_NODE_TRANSPILE_ONLY=1 hardhat test"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
cat -n package.json | sed -n '1,140p'
echo
printf '%s\n' '--- cross-env search ---'
rg -n '"cross-env"|cross-env' package.json package-lock.json pnpm-lock.yaml yarn.lock . 2>/dev/null | sed -n '1,120p'
echo
printf '%s\n' '--- os/docs search ---'
rg -n 'Windows|cross-platform|POSIX|npm run build|npm test|CI' README* docs .github package.json 2>/dev/null | sed -n '1,160p'

Repository: TrustVC/7702SmartAccount

Length of output: 3238


🌐 Web query:

npm scripts environment variable assignment Windows default shell TS_NODE_TRANSPILE_ONLY=1 cross-env documentation

💡 Result:

NPM scripts run in platform-dependent shells: /bin/sh on POSIX-compliant systems and cmd.exe on Windows [1][2]. Because these shells handle environment variable syntax differently (e.g., POSIX uses VAR=val command, while cmd.exe requires set VAR=val && command), hardcoding variables directly in your package.json scripts often leads to cross-platform compatibility issues [3][4][5]. To ensure your scripts work reliably across both Windows and POSIX environments, you should use the cross-env package [3][6][4]. cross-env Documentation and Usage cross-env allows you to set environment variables using POSIX syntax (e.g., NODE_ENV=production) in your npm scripts, and it automatically handles the necessary transformations to make them work on Windows [3][6][5]. To use it, add cross-env as a development dependency and prefix your command [5]: "scripts": { "start": "cross-env TS_NODE_TRANSPILE_ONLY=1 ts-node server.ts" } - cross-env and cross-env-shell: cross-env uses cross-spawn to execute commands, while cross-env-shell uses the shell option from Node's spawn [3][7]. Use cross-env-shell if you need to run multiple commands in series or require shell features like command substitution or signal handling [3][6][7]. TS_NODE_TRANSPILE_ONLY=1 The environment variable TS_NODE_TRANSPILE_ONLY is a recognized configuration for ts-node that enables fast execution by skipping type checking [8][9][10]. While you can set this variable directly in your environment, using it within an npm script requires cross-platform care. Using it with cross-env ensures that your script remains portable across different operating systems [3][5]. Recommended Alternative For better maintainability and to avoid platform-specific script syntax, ts-node recommends defining options directly in your tsconfig.json file [8][9][10]: { "ts-node": { "transpileOnly": true } } This approach is generally preferred over environment variables or command-line flags, as it allows you to configure behavior centrally without shell-dependent syntax [8][10].

Citations:


Make the npm scripts cross-platform
TS_NODE_TRANSPILE_ONLY=1 ... and rm -rf are POSIX-only, so npm run build, npm run test, and npm run clean fail in the default Windows shell. Use cross-env and rimraf or a small Node wrapper instead.

🤖 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 32 - 41, The npm scripts in package.json are using
POSIX-only shell syntax, which breaks on Windows. Update the build:sol,
build:abis, and test scripts to set TS_NODE_TRANSPILE_ONLY via a cross-platform
mechanism such as cross-env, and replace the clean script’s rm -rf with a
cross-platform delete approach like rimraf or a Node-based cleanup helper. Keep
the existing script names and wiring in place so build, test, and clean continue
to work consistently across shells.

Comment thread scripts/deployFactory.ts Outdated
Comment on lines +31 to +33
const deployer = privateKeyToAccount(
process.env.PRIVATE_KEY as `0x${string}`,
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Trim PRIVATE_KEY before use.

tdocDeployer and paymasterImpl are trimmed, but PRIVATE_KEY is not. Leading/trailing whitespace in the private key env var will cause privateKeyToAccount to fail with an opaque error.

   const deployer = privateKeyToAccount(
-    process.env.PRIVATE_KEY as `0x${string}`,
+    process.env.PRIVATE_KEY.trim() as `0x${string}`,
   );
📝 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.

Suggested change
const deployer = privateKeyToAccount(
process.env.PRIVATE_KEY as `0x${string}`,
);
const deployer = privateKeyToAccount(
process.env.PRIVATE_KEY.trim() as `0x${string}`,
);
🤖 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 `@scripts/deployFactory.ts` around lines 31 - 33, The PRIVATE_KEY handling in
deployFactory should be consistent with the trimmed account/env inputs used
elsewhere. Trim the process.env.PRIVATE_KEY value before passing it into
privateKeyToAccount in the deployer setup, and make sure the deployer
initialization path uses the sanitized string rather than the raw env var so
whitespace does not break account creation.

Comment thread scripts/deployImplementation.ts Outdated
Comment on lines +21 to +29
const DEFAULT_ENTRY_POINT =
"0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108" as `0x${string}`;

async function main() {
if (!process.env.PRIVATE_KEY) throw new Error("PRIVATE_KEY not set");
if (!process.env.SEPOLIA_RPC_URL) throw new Error("SEPOLIA_RPC_URL not set");

const entryPoint = (process.env.ENTRY_POINT ??
DEFAULT_ENTRY_POINT) as `0x${string}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Unify the EntryPoint source across the deployment scripts.

This implementation defaults to the Sepolia v0.8 EntryPoint, but the repo still has scripts/stakePlatformPaymaster.ts documented for EntryPoint v0.7. Running both flows against the same deployment will wire the paymaster to one EntryPoint and stake/fund it on another, which breaks sponsorship at runtime. Please centralize this value or require it explicitly everywhere.

🤖 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 `@scripts/deployImplementation.ts` around lines 21 - 29, The deployment flow is
using a default EntryPoint in `deployImplementation` that can diverge from the
one used by `stakePlatformPaymaster`, causing the paymaster to be
deployed/staked against different EntryPoints. Centralize the EntryPoint
selection in a shared constant or config used by both scripts, or require
`ENTRY_POINT` explicitly in both `main` functions so `DEFAULT_ENTRY_POINT`
cannot silently drift from the paymaster staking path.

Comment thread scripts/generate-abis.ts
Comment on lines +47 to +60
function main() {
if (fs.existsSync(OUT_DIR)) fs.rmSync(OUT_DIR, { recursive: true });
fs.mkdirSync(OUT_DIR, { recursive: true });

const indexLines: string[] = ["// Auto-generated by scripts/generate-abis.ts — do not edit manually\n"];

for (const { sol, contract, exportName, typeName } of CONTRACTS_TO_EXPORT) {
const artifactPath = path.join(ARTIFACTS_DIR, sol, `${contract}.json`);

if (!fs.existsSync(artifactPath)) {
console.error(`[generate-abis] Missing artifact: ${artifactPath}`);
console.error(" → Run `npm run build:sol` first.");
process.exit(1);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Validate artifacts before deleting src/abis.

This removes the generated sources first and only then checks whether each artifact exists. If one artifact is missing, src/index.ts still re-exports ./abis, so the repo is left in a broken state until generation is rerun. Validate all artifact paths up front, or write into a temp directory and swap on success.

🤖 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 `@scripts/generate-abis.ts` around lines 47 - 60, The main flow in main()
deletes OUT_DIR before verifying all CONTRACTS_TO_EXPORT artifacts exist, which
can leave src/index.ts pointing at a missing ./abis folder if validation fails.
Move the artifact existence checks for each artifactPath ahead of the
fs.rmSync/fs.mkdirSync cleanup, or generate into a temporary directory and only
replace OUT_DIR after all artifacts are confirmed and generation succeeds. Use
main, CONTRACTS_TO_EXPORT, OUT_DIR, and artifactPath to locate the fix.

Comment thread test/PlatformPaymaster.ts
Comment on lines +285 to +339
describe("mintDocument", function () {
it("mints a document, authorizes beneficiary+holder+escrow, increments counter", async function () {
const { paymaster, paymasterAsOther, mockRegistry, other, user } =
await loadFixture(deployFixture);

// Authorize the registry
await paymaster.write.addRegistry([mockRegistry.address]);

await paymasterAsOther.write.mintDocument([
mockRegistry.address,
user.account.address, // beneficiary
other.account.address, // holder
1n,
"0x" as `0x${string}`,
]);

expect(await paymaster.read.documentsMinted([other.account.address])).to.equal(1n);
expect(await paymaster.read.authorizedCallers([user.account.address])).to.be.true;
expect(await paymaster.read.authorizedCallers([other.account.address])).to.be.true;

// TitleEscrowLinked event tells us the escrow address
const events = await paymaster.getEvents.TitleEscrowLinked();
expect(events).to.have.lengthOf(1);
const escrow = events[0].args.titleEscrow as `0x${string}`;
expect(await paymaster.read.authorizedTitleEscrows([escrow])).to.be.true;
});

it("reverts for an unauthorized registry", async function () {
const { paymasterAsOther, mockRegistry, other, user } = await loadFixture(deployFixture);
await expect(
paymasterAsOther.write.mintDocument([
mockRegistry.address, // not yet authorized
user.account.address,
other.account.address,
1n,
"0x" as `0x${string}`,
]),
).to.be.rejectedWith("registry not authorized");
});

it("documentsMinted increments per caller", async function () {
const { paymaster, paymasterAsOther, mockRegistry, other, user } =
await loadFixture(deployFixture);
await paymaster.write.addRegistry([mockRegistry.address]);

await paymasterAsOther.write.mintDocument([
mockRegistry.address, user.account.address, other.account.address, 1n, "0x" as `0x${string}`,
]);
await paymasterAsOther.write.mintDocument([
mockRegistry.address, user.account.address, other.account.address, 2n, "0x" as `0x${string}`,
]);

expect(await paymaster.read.documentsMinted([other.account.address])).to.equal(2n);
});
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add coverage for the actual sponsorship gate, not just the mapping side effects.

These tests prove that mintDocument toggles authorizedCallers, but they never prove that _validatePaymasterUserOp now accepts those callers and rejects everyone else. A bug in the new sponsorship check would still leave this suite green.

🤖 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 `@test/PlatformPaymaster.ts` around lines 285 - 339, The mintDocument tests
only verify mapping updates and event side effects, so add coverage for the
actual sponsorship gate in _validatePaymasterUserOp. Extend the existing
mintDocument suite in PlatformPaymaster to assert that a user and holder
authorized by mintDocument are accepted by the paymaster validation path, and
that an unrelated caller is still rejected. Use the existing paymaster,
paymasterAsOther, authorizedCallers, and _validatePaymasterUserOp flow so the
test proves the new sponsorship check works end to end.

- semantic-release: add dev branch as beta prerelease channel
- release.yml: trigger workflow on dev pushes in addition to main
- README: full project documentation

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
README.md (3)

96-99: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Add a security warning about .env and private keys.

The setup instructions tell users to copy .env.example to .env and fill in PRIVATE_KEY, but there is no warning that .env must be git-ignored and that private keys should never be committed. This is a common foot-gun for developers new to the project.

 cp .env.example .env   # fill in PRIVATE_KEY, SEPOLIA_RPC_URL, PIMLICO_API_KEY
+
+# ⚠️ Never commit .env — it contains your private key!
🤖 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 `@README.md` around lines 96 - 99, Add a clear security warning in the setup
instructions near the `.env` setup step: explicitly state that `.env` must
remain git-ignored and that `PRIVATE_KEY` (and any other secrets) should never
be committed or shared. Update the README guidance around the `cp .env.example
.env` step so users know to keep secrets local and verify `.env` is excluded
from version control.

133-137: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Clarify prerequisites for gasless minting.

The "Mint a document gaslessly" section only provides a command with no context on what environment variables or prior steps are required. Users need at least PAYMASTER_ADDRESS, EIP7702_IMPL_ADDRESS, and likely the Pimlico API key already configured. Consider adding a brief note or sub-bullet listing the required env vars for this step.

🤖 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 `@README.md` around lines 133 - 137, The “Mint a document gaslessly” section
only shows the hardhat command and needs the missing setup context. Update the
README section for this step to mention the required prerequisites, including
the environment variables needed by scripts/mintDocumentGasless.ts such as
PAYMASTER_ADDRESS, EIP7702_IMPL_ADDRESS, and the Pimlico API key, and note any
prior configuration steps users must complete before running the command.

139-151: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document additional environment variables used by deployment scripts.

The environment variables table is missing several variables that the deployment scripts consume, which will cause runtime errors if users follow only the documented table:

  • PLATFORM_ADDRESS — defaults to deployer address in deployPlatformPaymaster.ts
  • DAILY_LIMIT_ETH — defaults to "0" (unlimited) in deployPlatformPaymaster.ts
  • DEPLOY_SALT — auto-generated if omitted in deployPlatformPaymaster.ts
  • STAKE_AMOUNT_ETH — defaults to "0.01" in stakePlatformPaymaster.ts
  • DEPOSIT_AMOUNT_ETH — defaults to "0.05" in stakePlatformPaymaster.ts
  • UNSTAKE_DELAY_SEC — defaults to "86400" in stakePlatformPaymaster.ts

Add these to the table with their descriptions and default values so users know what to configure.

🤖 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 `@README.md` around lines 139 - 151, The environment variables table in README
is missing several values used by the deployment scripts, so update the table to
include PLATFORM_ADDRESS, DAILY_LIMIT_ETH, DEPLOY_SALT, STAKE_AMOUNT_ETH,
DEPOSIT_AMOUNT_ETH, and UNSTAKE_DELAY_SEC. Refer to the deployment logic in
deployPlatformPaymaster.ts and stakePlatformPaymaster.ts when adding each entry,
and make sure the descriptions include the documented defaults or behavior (for
example, deployer address fallback, “0” unlimited, auto-generated salt, and the
stake/deposit/delay defaults).
🤖 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.

Nitpick comments:
In `@README.md`:
- Around line 96-99: Add a clear security warning in the setup instructions near
the `.env` setup step: explicitly state that `.env` must remain git-ignored and
that `PRIVATE_KEY` (and any other secrets) should never be committed or shared.
Update the README guidance around the `cp .env.example .env` step so users know
to keep secrets local and verify `.env` is excluded from version control.
- Around line 133-137: The “Mint a document gaslessly” section only shows the
hardhat command and needs the missing setup context. Update the README section
for this step to mention the required prerequisites, including the environment
variables needed by scripts/mintDocumentGasless.ts such as PAYMASTER_ADDRESS,
EIP7702_IMPL_ADDRESS, and the Pimlico API key, and note any prior configuration
steps users must complete before running the command.
- Around line 139-151: The environment variables table in README is missing
several values used by the deployment scripts, so update the table to include
PLATFORM_ADDRESS, DAILY_LIMIT_ETH, DEPLOY_SALT, STAKE_AMOUNT_ETH,
DEPOSIT_AMOUNT_ETH, and UNSTAKE_DELAY_SEC. Refer to the deployment logic in
deployPlatformPaymaster.ts and stakePlatformPaymaster.ts when adding each entry,
and make sure the descriptions include the documented defaults or behavior (for
example, deployer address fallback, “0” unlimited, auto-generated salt, and the
stake/deposit/delay defaults).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f8424238-bbd5-4125-b5a4-4a81c3934e0b

📥 Commits

Reviewing files that changed from the base of the PR and between aff13bb and 8beccb4.

📒 Files selected for processing (4)
  • .github/workflows/release.yml
  • .gitignore
  • README.md
  • package.json
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/release.yml
  • package.json

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
.github/workflows/release.yml (1)

30-48: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Harden the release install step
npm ci will run install hooks from locked dependencies (esbuild, keccak, secp256k1, etc.) inside a job with write permissions. Match the other workflows and use npm ci --ignore-scripts here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 30 - 48, The release workflow’s
install step currently runs dependency hooks during npm ci, which is
inconsistent with the other workflows and increases risk in a write-enabled job.
Update the install command in the release job to use npm ci --ignore-scripts,
keeping the existing setup around actions/checkout, actions/cache, and
actions/setup-node unchanged.
🧹 Nitpick comments (5)
.env.example (1)

29-29: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Quote string value containing spaces.

REMARK=optional remark text should be quoted to prevent parsing ambiguities with certain dotenv parsers or special characters.

-REMARK=optional remark text
+REMARK="optional remark text"
🤖 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 @.env.example at line 29, The REMARK example in the .env.example snippet is
an unquoted string with spaces, which can be parsed inconsistently by dotenv
tools. Update the REMARK entry to use a quoted value in the example so it is
unambiguous and matches the expected formatting for spaced strings.
.github/workflows/release.yml (1)

35-42: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Cache npm’s package store instead of node_modules. npm ci installs into the workspace and clears node_modules, so this cache won’t help; setup-node with cache: npm is the better fit.

🤖 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 @.github/workflows/release.yml around lines 35 - 42, The caching step in the
release workflow is targeting node_modules, but this does not help with npm ci
because it recreates the workspace install and clears that directory. Update the
cache strategy in the release workflow to use npm’s package store via setup-node
with cache: npm, and remove the actions/cache@v4 node_modules cache so the
workflow uses the built-in npm cache instead.
scripts/lib/network.ts (2)

38-43: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add address-format validation to getEnv consumers.

Callers cast the raw string straight to `0x${string}` with no validation. A malformed .env value fails with an opaque viem error deep in the script rather than a clear message here.

♻️ Suggested addition
+import { isAddress } from "viem";
+
 export function getEnv(suffix: string, name: string, required = true): string {
   const key = `${name}_${suffix}`;
   const val = process.env[key]?.trim();
   if (!val && required) throw new Error(`${key} is not set in .env`);
   return val ?? "";
 }
+
+/** Read and validate a network-specific address env var. */
+export function getAddressEnv(suffix: string, name: string): `0x${string}` {
+  const val = getEnv(suffix, name);
+  if (!isAddress(val)) throw new Error(`${name}_${suffix} is not a valid address: "${val}"`);
+  return val as `0x${string}`;
+}
🤖 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 `@scripts/lib/network.ts` around lines 38 - 43, The raw env lookup in getEnv is
being cast directly to an address type by its callers without validation, so add
explicit address-format checking at the consumer sites before the `0x${string}`
cast. Update the scripts that call getEnv to validate the returned value with
the existing address parsing/validation flow and throw a clear local error when
the value is malformed, rather than letting viem fail later.

1-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Consider centralizing the duplicated EIP-7702 delegation/bootstrap flow.

The "check current delegate → redelegate if needed → to7702SimpleSmartAccountcreateSmartAccountClient" block is repeated almost identically in deployRegistryGasless.ts, mintDocumentGasless.ts, and trFunctions/_setup.ts's buildClient(). Since this file already centralizes network/env resolution, it's a reasonable home for a shared bootstrap helper to reduce triplicated logic.

🤖 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 `@scripts/lib/network.ts` around lines 1 - 43, The EIP-7702 bootstrap flow is
duplicated across deployRegistryGasless.ts, mintDocumentGasless.ts, and
trFunctions/_setup.ts buildClient(), so move the shared “check current delegate
→ redelegate if needed → to7702SimpleSmartAccount → createSmartAccountClient”
logic into a reusable helper in scripts/lib/network.ts or a nearby shared
module. Expose a small function that accepts the network config and
account/client inputs, returns the configured smart account client, and have the
three call sites use it instead of inlining the sequence. Keep network/env
resolution in getNetworkConfig and getEnv, but centralize the repeated
delegation setup behind one named helper to avoid drift.
scripts/trFunctions/_setup.ts (1)

5-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document TITLE_ESCROW_ADDRESS_<NETWORK> env var.

getTRContract(suffix) (Line 119) requires TITLE_ESCROW_ADDRESS_<suffix> via getEnv, but the header env-var list omits it, unlike PAYMASTER_ADDRESS_<NETWORK> which is documented.

📝 Proposed doc fix
 //   PAYMASTER_ADDRESS_<NETWORK>  — deployed PlatformPaymaster (v0.8 EntryPoint)
+//   TITLE_ESCROW_ADDRESS_<NETWORK> — target TitleEscrow contract for tr* scripts
 //   PRIVATE_KEY                  — funded wallet (pays gas for delegation tx if needed)
🤖 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 `@scripts/trFunctions/_setup.ts` around lines 5 - 10, The env-var header in
_setup.ts is missing TITLE_ESCROW_ADDRESS_<NETWORK>, even though
getTRContract(suffix) depends on TITLE_ESCROW_ADDRESS_<suffix> via getEnv.
Update the documented environment variable list near the top of the file to
include TITLE_ESCROW_ADDRESS_<NETWORK>, matching the style used for
PAYMASTER_ADDRESS_<NETWORK>, so users can configure the required escrow address
for each network.
🤖 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 @.env.example:
- Line 71: Remove the duplicated FACTORY_ADDRESS_AMOY entry from the “Filled in
after running gasless scripts” section in .env.example so it is defined only
once in the deployments section, matching the Sepolia pattern; keep only
REGISTRY_ADDRESS_AMOY and TITLE_ESCROW_ADDRESS_AMOY there, and preserve the
existing FACTORY_ADDRESS_AMOY value defined earlier.

In @.github/workflows/release.yml:
- Line 50: The release workflow is running semantic-release on a branch that is
not configured for releases. Update the semantic-release configuration to
include the dev branch, or change the release job in the workflow so the
semantic-release step only runs on branches already configured for release; use
the semantic-release invocation in the release workflow to locate the change.

---

Outside diff comments:
In @.github/workflows/release.yml:
- Around line 30-48: The release workflow’s install step currently runs
dependency hooks during npm ci, which is inconsistent with the other workflows
and increases risk in a write-enabled job. Update the install command in the
release job to use npm ci --ignore-scripts, keeping the existing setup around
actions/checkout, actions/cache, and actions/setup-node unchanged.

---

Nitpick comments:
In @.env.example:
- Line 29: The REMARK example in the .env.example snippet is an unquoted string
with spaces, which can be parsed inconsistently by dotenv tools. Update the
REMARK entry to use a quoted value in the example so it is unambiguous and
matches the expected formatting for spaced strings.

In @.github/workflows/release.yml:
- Around line 35-42: The caching step in the release workflow is targeting
node_modules, but this does not help with npm ci because it recreates the
workspace install and clears that directory. Update the cache strategy in the
release workflow to use npm’s package store via setup-node with cache: npm, and
remove the actions/cache@v4 node_modules cache so the workflow uses the built-in
npm cache instead.

In `@scripts/lib/network.ts`:
- Around line 38-43: The raw env lookup in getEnv is being cast directly to an
address type by its callers without validation, so add explicit address-format
checking at the consumer sites before the `0x${string}` cast. Update the scripts
that call getEnv to validate the returned value with the existing address
parsing/validation flow and throw a clear local error when the value is
malformed, rather than letting viem fail later.
- Around line 1-43: The EIP-7702 bootstrap flow is duplicated across
deployRegistryGasless.ts, mintDocumentGasless.ts, and trFunctions/_setup.ts
buildClient(), so move the shared “check current delegate → redelegate if needed
→ to7702SimpleSmartAccount → createSmartAccountClient” logic into a reusable
helper in scripts/lib/network.ts or a nearby shared module. Expose a small
function that accepts the network config and account/client inputs, returns the
configured smart account client, and have the three call sites use it instead of
inlining the sequence. Keep network/env resolution in getNetworkConfig and
getEnv, but centralize the repeated delegation setup behind one named helper to
avoid drift.

In `@scripts/trFunctions/_setup.ts`:
- Around line 5-10: The env-var header in _setup.ts is missing
TITLE_ESCROW_ADDRESS_<NETWORK>, even though getTRContract(suffix) depends on
TITLE_ESCROW_ADDRESS_<suffix> via getEnv. Update the documented environment
variable list near the top of the file to include
TITLE_ESCROW_ADDRESS_<NETWORK>, matching the style used for
PAYMASTER_ADDRESS_<NETWORK>, so users can configure the required escrow address
for each network.
🪄 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

Run ID: 8b9e8174-9775-41a2-86cc-f416d71d459d

📥 Commits

Reviewing files that changed from the base of the PR and between 8beccb4 and e28142a.

📒 Files selected for processing (34)
  • .env.example
  • .github/workflows/linters.yml
  • .github/workflows/release.yml
  • .github/workflows/tests.yml
  • EIP7702_METAMASK_ARCHITECTURE.md
  • PIMLICO_EIP7702_DOCS.md
  • contracts/Etherspot/BasePaymaster.sol
  • contracts/Etherspot/EtherspotPaymaster.sol
  • contracts/Etherspot/core/Helpers.sol
  • contracts/Etherspot/core/UserOperationLib.sol
  • contracts/Etherspot/interfaces/IAggregator.sol
  • contracts/Etherspot/interfaces/IEntryPoint.sol
  • contracts/Etherspot/interfaces/INonceManager.sol
  • contracts/Etherspot/interfaces/IPaymaster.sol
  • contracts/Etherspot/interfaces/IStakeManager.sol
  • contracts/Etherspot/interfaces/PackedUserOperation.sol
  • hardhat.config.ts
  • scripts/deployEIP7702.ts
  • scripts/deployFactory.ts
  • scripts/deployImplementation.ts
  • scripts/deployPlatformPaymaster.ts
  • scripts/deployRegistryGasless.ts
  • scripts/lib/network.ts
  • scripts/mintDocumentGasless.ts
  • scripts/stakePlatformPaymaster.ts
  • scripts/trFunctions/_setup.ts
  • scripts/trFunctions/nominate.ts
  • scripts/trFunctions/rejectTransferBeneficiary.ts
  • scripts/trFunctions/rejectTransferHolder.ts
  • scripts/trFunctions/rejectTransferOwners.ts
  • scripts/trFunctions/returnToIssuer.ts
  • scripts/trFunctions/shred.ts
  • scripts/trFunctions/transferBeneficiary.ts
  • scripts/trFunctions/transferOwners.ts
💤 Files with no reviewable changes (12)
  • contracts/Etherspot/interfaces/PackedUserOperation.sol
  • contracts/Etherspot/interfaces/IAggregator.sol
  • contracts/Etherspot/interfaces/IPaymaster.sol
  • contracts/Etherspot/interfaces/INonceManager.sol
  • contracts/Etherspot/interfaces/IStakeManager.sol
  • PIMLICO_EIP7702_DOCS.md
  • contracts/Etherspot/EtherspotPaymaster.sol
  • contracts/Etherspot/core/UserOperationLib.sol
  • contracts/Etherspot/BasePaymaster.sol
  • contracts/Etherspot/core/Helpers.sol
  • contracts/Etherspot/interfaces/IEntryPoint.sol
  • EIP7702_METAMASK_ARCHITECTURE.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • .github/workflows/tests.yml
  • .github/workflows/linters.yml
  • scripts/deployImplementation.ts
  • scripts/deployFactory.ts

Comment thread .env.example
# Filled in after running gasless scripts with NETWORK=amoy
REGISTRY_ADDRESS_AMOY=0x_filled_after_deployRegistry
TITLE_ESCROW_ADDRESS_AMOY=0x_filled_after_mintDocument
FACTORY_ADDRESS_AMOY=0x_filled_after_deployFactory

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Remove duplicated FACTORY_ADDRESS_AMOY key.

Line 61 already defines FACTORY_ADDRESS_AMOY=0x_filled_by_deployFactory. The duplicate at line 71 with a different placeholder value will overwrite the first definition. Following the Sepolia pattern (lines 43–54), the factory address should only appear once in the deployments section; the "Filled in after running gasless scripts" section should contain only REGISTRY_ADDRESS_AMOY and TITLE_ESCROW_ADDRESS_AMOY.

-# Filled in after running gasless scripts with NETWORK=amoy
-REGISTRY_ADDRESS_AMOY=0x_filled_after_deployRegistry
-TITLE_ESCROW_ADDRESS_AMOY=0x_filled_after_mintDocument
-FACTORY_ADDRESS_AMOY=0x_filled_after_deployFactory
+# Filled in after running gasless scripts with NETWORK=amoy
+REGISTRY_ADDRESS_AMOY=0x_filled_after_deployRegistry
+TITLE_ESCROW_ADDRESS_AMOY=0x_filled_after_mintDocument
📝 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.

Suggested change
FACTORY_ADDRESS_AMOY=0x_filled_after_deployFactory
# Filled in after running gasless scripts with NETWORK=amoy
REGISTRY_ADDRESS_AMOY=0x_filled_after_deployRegistry
TITLE_ESCROW_ADDRESS_AMOY=0x_filled_after_mintDocument
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 71-71: [DuplicatedKey] The FACTORY_ADDRESS_AMOY key is duplicated

(DuplicatedKey)


[warning] 71-71: [UnorderedKey] The FACTORY_ADDRESS_AMOY key should go before the REGISTRY_ADDRESS_AMOY key

(UnorderedKey)

🤖 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 @.env.example at line 71, Remove the duplicated FACTORY_ADDRESS_AMOY entry
from the “Filled in after running gasless scripts” section in .env.example so it
is defined only once in the deployments section, matching the Sepolia pattern;
keep only REGISTRY_ADDRESS_AMOY and TITLE_ESCROW_ADDRESS_AMOY there, and
preserve the existing FACTORY_ADDRESS_AMOY value defined earlier.


- run: npm ci
- run: npm run build
- run: npm run semantic-release

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n --glob 'package.json' --glob '.releaserc*' --glob 'release.config.*' 'semantic-release|branches|dev|main'

Repository: TrustVC/7702SmartAccount

Length of output: 162


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== top-level files =="
git ls-files | sed -n '1,200p'

echo
echo "== semantic-release related files =="
git ls-files | rg '(^|/)(package\.json|\.releaserc(\.[^/]+)?|release\.config\.[^/]+|.*release.*\.yml|.*release.*\.yaml)$'

echo
echo "== search for release config terms =="
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' 'semantic-release|release\.branches|branches\s*:' .

echo
echo "== workflow snippet =="
sed -n '1,140p' .github/workflows/release.yml

Repository: TrustVC/7702SmartAccount

Length of output: 8449


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== semantic-release related files =="
git ls-files | rg '(^|/)(package\.json|\.releaserc(\.[^/]+)?|release\.config\.[^/]+|.*release.*\.yml|.*release.*\.yaml)$' || true

echo
echo "== search for release config terms =="
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' 'semantic-release|release\.branches|branches\s*:' . || true

echo
echo "== workflow snippet =="
sed -n '1,140p' .github/workflows/release.yml

Repository: TrustVC/7702SmartAccount

Length of output: 6610


Restrict semantic-release to configured branches
.github/workflows/release.yml triggers on dev, but there’s no repo-level semantic-release branches config for it. Either add dev to the release config or stop running this job on that branch.

🤖 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 @.github/workflows/release.yml at line 50, The release workflow is running
semantic-release on a branch that is not configured for releases. Update the
semantic-release configuration to include the dev branch, or change the release
job in the workflow so the semantic-release step only runs on branches already
configured for release; use the semantic-release invocation in the release
workflow to locate the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant