From 1004d328ca509448ba6f9442bd9312bf75fb876c Mon Sep 17 00:00:00 2001 From: Rishabh Singh Date: Thu, 2 Jul 2026 16:03:57 +0530 Subject: [PATCH 1/3] feat: add EIP-7702 gasless operations documentation Adds a new "Gasless (EIP-7702)" section to the sidebar with three pages: - overview: architecture, deployed addresses for Sepolia and Polygon Amoy, SDK install - setup: deployPlatformPaymaster, staking, user whitelisting, building smartAccountClient - gasless-operations: code examples for all 12 SDK functions --- docs/eip7702/gasless-operations.md | 258 +++++++++++++++++++++++++++++ docs/eip7702/overview.md | 108 ++++++++++++ docs/eip7702/setup.md | 222 +++++++++++++++++++++++++ sidebars.json | 5 + 4 files changed, 593 insertions(+) create mode 100644 docs/eip7702/gasless-operations.md create mode 100644 docs/eip7702/overview.md create mode 100644 docs/eip7702/setup.md diff --git a/docs/eip7702/gasless-operations.md b/docs/eip7702/gasless-operations.md new file mode 100644 index 0000000..6c57b02 --- /dev/null +++ b/docs/eip7702/gasless-operations.md @@ -0,0 +1,258 @@ +--- +id: gasless-operations +title: Gasless Operations +sidebar_label: Gasless Operations +--- + +# Gasless Operations + +All functions on this page accept a `smartAccountClient` built as described in [Setup](./setup). They return a `Promise` containing the UserOp transaction hash. + +:::tip Remarks encryption +All `remarks` strings are automatically encrypted with the document ID (`options.id`) before being sent on-chain. Pass the document's `id` in the `TransactionOptions` argument whenever remarks are present. +::: + +--- + +## Deploy a Token Registry + +Deploys a new `TradeTrustToken` registry clone through the `PlatformPaymaster`. The caller must have at least 1 deployment credit (`setUserWhitelist`). + +```ts +import { deployTokenRegistryGasless } from '@trustvc/trustvc'; + +const txHash = await deployTokenRegistryGasless( + 'My Shipping Line', // registry name + 'MSL', // registry symbol + smartAccountClient, + { + paymasterAddress: '0xYourPaymaster...', + tokenRegistryImplAddress: '0x64bc665056DC8bE4092e569ED13a7F273Be28cD2', // TDocDeployer on Sepolia + }, +); +``` + +The `RegistryDeployed(user, deployed, creditsLeft)` event is emitted by the paymaster. Parse it from the receipt to get the deployed registry address. + +--- + +## Mint a Document + +Mints a new trade document on an authorized registry. Automatically authorizes the beneficiary, holder, and the new `TitleEscrow` on the paymaster. + +```ts +import { mintGasless } from '@trustvc/trustvc'; + +const txHash = await mintGasless( + { + paymasterAddress: '0xYourPaymaster...', + tokenRegistryAddress: '0xYourRegistry...', + }, + smartAccountClient, + { + beneficiaryAddress: '0xBeneficiary...', + holderAddress: '0xHolder...', + tokenId: '0xdeadbeef', // or a BigInt + remarks: 'Initial issuance', // optional + }, + { id: 'document-uuid' }, // used to encrypt remarks +); +``` + +The `TitleEscrowLinked(titleEscrow, registry)` event is emitted. Parse it to get the deployed `TitleEscrow` address. + +--- + +## Title Escrow Operations + +All operations below target the `TitleEscrow` contract directly. The `smartAccountClient` owner must be the current holder or beneficiary as appropriate. + +### Transfer Holder + +Transfers the **holder** role to a new address. Caller must be the current holder. + +```ts +import { transferHolderGasless } from '@trustvc/trustvc'; + +const txHash = await transferHolderGasless( + { titleEscrowAddress: '0xTitleEscrow...' }, + smartAccountClient, + { + holderAddress: '0xNewHolder...', + remarks: 'Transferring to freight forwarder', // optional + }, + { id: 'document-uuid' }, +); +``` + +### Transfer Beneficiary (Nominate) + +Nominates a new beneficiary. Caller must be the current beneficiary. + +```ts +import { transferBeneficiaryGasless } from '@trustvc/trustvc'; + +const txHash = await transferBeneficiaryGasless( + { titleEscrowAddress: '0xTitleEscrow...' }, + smartAccountClient, + { + newBeneficiaryAddress: '0xNewBeneficiary...', + remarks: 'Endorsing to buyer', // optional + }, + { id: 'document-uuid' }, +); +``` + +### Transfer Both Owners + +Transfers holder and beneficiary in one transaction. Caller must be both holder and beneficiary. + +```ts +import { transferOwnersGasless } from '@trustvc/trustvc'; + +const txHash = await transferOwnersGasless( + { titleEscrowAddress: '0xTitleEscrow...' }, + smartAccountClient, + { + newBeneficiaryAddress: '0xNewBeneficiary...', + newHolderAddress: '0xNewHolder...', + remarks: 'Full transfer', // optional + }, + { id: 'document-uuid' }, +); +``` + +### Nominate a Beneficiary + +Nominates a beneficiary without immediately completing the transfer. The nominated beneficiary must accept separately. + +```ts +import { nominateGasless } from '@trustvc/trustvc'; + +const txHash = await nominateGasless( + { titleEscrowAddress: '0xTitleEscrow...' }, + smartAccountClient, + { + newBeneficiaryAddress: '0xNominatedBeneficiary...', + remarks: 'Nomination for endorsement', // optional + }, + { id: 'document-uuid' }, +); +``` + +### Reject a Pending Transfer — Holder + +Rejects a pending holder transfer. Caller must be the current holder. + +```ts +import { rejectTransferHolderGasless } from '@trustvc/trustvc'; + +const txHash = await rejectTransferHolderGasless( + { titleEscrowAddress: '0xTitleEscrow...' }, + smartAccountClient, + { remarks: 'Rejecting transfer' }, // optional + { id: 'document-uuid' }, +); +``` + +### Reject a Pending Transfer — Beneficiary + +Rejects a pending beneficiary (nomination). Caller must be the current beneficiary. + +```ts +import { rejectTransferBeneficiaryGasless } from '@trustvc/trustvc'; + +const txHash = await rejectTransferBeneficiaryGasless( + { titleEscrowAddress: '0xTitleEscrow...' }, + smartAccountClient, + { remarks: 'Rejecting nomination' }, + { id: 'document-uuid' }, +); +``` + +### Reject a Pending Transfer — Both Owners + +Rejects a pending combined transfer. Caller must be both current holder and beneficiary. + +```ts +import { rejectTransferOwnersGasless } from '@trustvc/trustvc'; + +const txHash = await rejectTransferOwnersGasless( + { titleEscrowAddress: '0xTitleEscrow...' }, + smartAccountClient, + { remarks: 'Rejecting combined transfer' }, + { id: 'document-uuid' }, +); +``` + +--- + +## Return to Issuer + +At the end of a document's lifecycle, the holder (who is also the beneficiary) returns the token to the issuer. + +```ts +import { returnToIssuerGasless } from '@trustvc/trustvc'; + +const txHash = await returnToIssuerGasless( + { titleEscrowAddress: '0xTitleEscrow...' }, + smartAccountClient, + { remarks: 'Surrendering document' }, // optional + { id: 'document-uuid' }, +); +``` + +### Reject a Returned Document + +The platform (registry admin) restores the document back to the title escrow, rejecting the return. + +```ts +import { rejectReturnedGasless } from '@trustvc/trustvc'; + +const txHash = await rejectReturnedGasless( + { tokenRegistryAddress: '0xYourRegistry...' }, + smartAccountClient, + { + tokenId: '0xdeadbeef', + remarks: 'Return rejected', // optional + }, + { id: 'document-uuid' }, +); +``` + +### Accept a Returned Document (Burn) + +The platform accepts the return and burns the document. + +```ts +import { acceptReturnedGasless } from '@trustvc/trustvc'; + +const txHash = await acceptReturnedGasless( + { tokenRegistryAddress: '0xYourRegistry...' }, + smartAccountClient, + { + tokenId: '0xdeadbeef', + remarks: 'Document accepted and destroyed', // optional + }, + { id: 'document-uuid' }, +); +``` + +--- + +## Summary + +| Function | Target | Caller | +|---|---|---| +| `deployTokenRegistryGasless` | PlatformPaymaster | Whitelisted user | +| `mintGasless` | PlatformPaymaster | User with MINTER_ROLE | +| `transferHolderGasless` | TitleEscrow | Current holder | +| `transferBeneficiaryGasless` | TitleEscrow | Current beneficiary | +| `transferOwnersGasless` | TitleEscrow | Holder and beneficiary | +| `nominateGasless` | TitleEscrow | Current beneficiary | +| `rejectTransferHolderGasless` | TitleEscrow | Current holder | +| `rejectTransferBeneficiaryGasless` | TitleEscrow | Current beneficiary | +| `rejectTransferOwnersGasless` | TitleEscrow | Holder and beneficiary | +| `returnToIssuerGasless` | TitleEscrow | Holder = beneficiary | +| `rejectReturnedGasless` | Token Registry | Registry admin | +| `acceptReturnedGasless` | Token Registry | Registry admin | diff --git a/docs/eip7702/overview.md b/docs/eip7702/overview.md new file mode 100644 index 0000000..ed4bb80 --- /dev/null +++ b/docs/eip7702/overview.md @@ -0,0 +1,108 @@ +--- +id: overview +title: Gasless Operations (EIP-7702) +sidebar_label: Overview +--- + +# Gasless Operations with EIP-7702 + +:::caution Beta +Gasless transactions are currently in **beta**. APIs, contract addresses, and behavior may change before the stable release. Use on testnet only and do not rely on this feature in production. +::: + +TrustVC supports **gasless trade document operations** via [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) (smart account delegation). Users can deploy token registries, mint documents, and perform all title escrow operations without holding ETH — gas is sponsored by a **PlatformPaymaster**. + +## Architecture + +The system is built on three smart contracts: + +| Contract | Role | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `EIP7702Implementation` | Shared smart account logic. EOAs delegate to this once via a type-4 transaction — their bytecode becomes `0xef0100 \|\| impl_address`, giving them full smart-account capability while keeping the same address and private key. | +| `PlatformPaymaster` | Per-platform ERC-4337 paymaster deployed as a minimal-proxy clone. Sponsors gas for registry deploys, mints, and title escrow operations within configured limits. | +| `PlatformAccountFactory` | Deploys `PlatformPaymaster` clones deterministically via `CREATE2`. Cheap (~55 k gas) and the clone address is predictable before deployment. | + +## How it works + +``` +User (EOA, no ETH) + │ + │ 1. Sign EIP-7702 authorization → EOA delegates to EIP7702Implementation + │ 2. Submit UserOperation via Pimlico bundler + │ + ▼ +Bundler (Pimlico) + │ + │ 3. Calls EntryPoint → validates against PlatformPaymaster + │ + ▼ +PlatformPaymaster + │ + ├── Path A — Title escrow / registry calls + │ Checks: caller ∈ authorizedCallers, target ∈ authorizedRegistries or authorizedTitleEscrows + │ Enforces: dailyLimit per user + │ + └── Path B — deployRegistry / mintDocument on the paymaster itself + deployRegistry: userWhitelist[sender] > 0 (platform whitelists users) + mintDocument: caller has MINTER_ROLE on the registry +``` + +## Deployed addresses + +### Sepolia (chainId: 11155111) + +| Contract | Address | +| ---------------------------------- | -------------------------------------------- | +| EIP7702Implementation | `0xa46EC3920Ac5fc54F4bA33185A91ae250aDF59B8` | +| PlatformPaymaster (implementation) | `0xa24695178ea881ab7d4d105106e4906a8da4752b` | +| PlatformAccountFactory | `0x7e9ef6363180baa744eb32ceab367a44f52adc9f` | +| TDocDeployer | `0x64bc665056DC8bE4092e569ED13a7F273Be28cD2` | +| EntryPoint v0.8 | `0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108` | + +### Polygon Amoy (chainId: 80002) + +| Contract | Address | +| ---------------------------------- | -------------------------------------------- | +| EIP7702Implementation | `0x044de1d4515a76ed9e431e8ec89e8d600405fd86` | +| PlatformPaymaster (implementation) | `0x1c4367128933E9a88de26C723F50C288fA0fFea7` | +| PlatformAccountFactory | `0xfbe1d336000d567f98ac5318f7c0144501388409` | +| TDocDeployer | `0xfcafea839e576967b96ad1FBFB52b5CA26cd1D25` | +| EntryPoint v0.8 | `0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108` | + +## SDK package + +The `@trustvc/trustvc` SDK exposes all gasless functions under the `eip7702-functions` namespace. Install it once: + +```bash +npm install @trustvc/trustvc +``` + +Import any gasless function directly: + +```ts +import { + deployTokenRegistryGasless, + mintGasless, + transferHolderGasless, + transferBeneficiaryGasless, + transferOwnersGasless, + nominateGasless, + returnToIssuerGasless, + rejectReturnedGasless, + acceptReturnedGasless, + rejectTransferHolderGasless, + rejectTransferBeneficiaryGasless, + rejectTransferOwnersGasless, +} from "@trustvc/trustvc"; +``` + +## Prerequisites + +Before calling any gasless function you need: + +1. **A PlatformPaymaster deployed for your platform** — see [Setup](./setup). +2. **A Pimlico API key** — free tier at [dashboard.pimlico.io](https://dashboard.pimlico.io). +3. **The user's EOA delegated** — one-time type-4 transaction (wallet signs an EIP-7702 authorization). +4. **A built `smartAccountClient`** — the permissionless `SmartAccountClient` wrapping the delegated EOA. + +All four are covered in [Setup](./setup). Once set up, jump to [Gasless Operations](./gasless-operations) for code examples. diff --git a/docs/eip7702/setup.md b/docs/eip7702/setup.md new file mode 100644 index 0000000..b1c5286 --- /dev/null +++ b/docs/eip7702/setup.md @@ -0,0 +1,222 @@ +--- +id: setup +title: Setup +sidebar_label: Setup +--- + +# Setup + +This page walks through one-time setup steps: deploying a PlatformPaymaster for your platform, whitelisting users, and building the `smartAccountClient` that all gasless SDK functions accept. + +## 1. Deploy a PlatformPaymaster + +Each platform (issuer) deploys its own `PlatformPaymaster` clone via `PlatformAccountFactory`. The clone is a cheap minimal proxy (~55 k gas) with its own state (owner, daily limit, authorized registries). + +### Using the SDK + +```ts +import { deployPlatformPaymaster } from '@trustvc/trustvc'; +import { createWalletClient, createPublicClient, http } from 'viem'; +import { sepolia } from 'viem/chains'; +import { privateKeyToAccount } from 'viem/accounts'; + +const deployer = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`); + +const walletClient = createWalletClient({ + account: deployer, + chain: sepolia, + transport: http(process.env.SEPOLIA_RPC_URL), +}); + +const publicClient = createPublicClient({ + chain: sepolia, + transport: http(process.env.SEPOLIA_RPC_URL), +}); + +const { txHash, paymasterAddress } = await deployPlatformPaymaster( + walletClient, + { + // factoryAddress defaults to the Sepolia PlatformAccountFactory if omitted + platformAddress: deployer.address, // EOA that owns the paymaster + dailyLimit: 0n, // 0 = unlimited; set in wei if you want a cap + salt: `0x${'ab'.repeat(32)}`, // bytes32 CREATE2 salt — must be unique per platform + }, + publicClient, +); + +console.log('Paymaster deployed at:', paymasterAddress); +console.log('Tx:', txHash); +``` + +The function also accepts an ethers v5 or v6 signer in place of the viem `WalletClient`. + +### Options + +| Option | Required | Description | +|---|---|---| +| `salt` | Yes | `bytes32` CREATE2 salt. Use `crypto.randomBytes(32).toString('hex')` for a random one. | +| `platformAddress` | No | Paymaster owner. Defaults to the signer's address. | +| `dailyLimit` | No | Per-user daily gas spend cap in wei. `0n` = unlimited. | +| `factoryAddress` | No | Override factory address. Defaults to Sepolia's deployed factory. | +| `chainId` | No | Used to auto-resolve `factoryAddress`. Defaults to Sepolia. | + +## 2. Stake the paymaster on EntryPoint + +The paymaster must hold a deposit on the EntryPoint to sponsor UserOps. Stake it once after deployment using a funded EOA: + +```ts +import { parseAbi, createWalletClient, http } from 'viem'; +import { sepolia } from 'viem/chains'; + +const entryPointAbi = parseAbi([ + 'function depositTo(address account) external payable', + 'function addStake(uint32 unstakeDelaySec) external payable', +]); + +const ENTRY_POINT = '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108'; + +// Deposit ETH to cover gas sponsorship +await walletClient.writeContract({ + address: ENTRY_POINT, + abi: entryPointAbi, + functionName: 'depositTo', + args: [paymasterAddress], + value: parseEther('0.1'), // adjust as needed +}); + +// Stake for ERC-4337 compliance +await walletClient.writeContract({ + address: ENTRY_POINT, + abi: entryPointAbi, + functionName: 'addStake', + args: [86400], // 1-day unstake delay + value: parseEther('0.001'), + account: deployerAccount, + chain: sepolia, +}); +``` + +## 3. Whitelist users (admin) + +The paymaster owner must whitelist users before they can deploy registries gaslessly. Credits represent how many registry deployments are allowed per user (max 3). + +```ts +import { setUserWhitelist } from '@trustvc/trustvc'; + +// Whitelist a user with 2 deployment credits +await setUserWhitelist( + ownerWalletClient, // platform owner signer + paymasterAddress, // your PlatformPaymaster + '0xUserAddress...', // user to whitelist + 2n, // credits (0–3) +); +``` + +Other admin functions available from `@trustvc/trustvc`: + +```ts +import { + removeUserFromWhitelist, + addRegistry, + removeRegistry, + addTitleEscrow, + removeTitleEscrow, + addAuthorizedCaller, + removeAuthorizedCaller, + setDailyLimit, +} from '@trustvc/trustvc'; +``` + +All admin functions accept an ethers v5/v6 signer or viem `WalletClient` as the first argument and return `Promise` (tx hash). + +## 4. Build a smart account client + +All gasless SDK functions take a `smartAccountClient` as their second argument. Build one from the user's delegated EOA using **permissionless** + **Pimlico**: + +```ts +import { + createPublicClient, + createWalletClient, + custom, + http, +} from 'viem'; +import { sepolia } from 'viem/chains'; +import { entryPoint08Address } from 'viem/account-abstraction'; +import { createPimlicoClient } from 'permissionless/clients/pimlico'; +import { createSmartAccountClient } from 'permissionless'; +import { to7702SimpleSmartAccount } from 'permissionless/accounts'; + +const PIMLICO_URL = `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${PIMLICO_API_KEY}`; +// EIP-7702 implementation deployed by permissionless team +const PERMISSIONLESS_IMPL = '0xe6Cae83BdE06E4c305530e199D7217f42808555B'; + +async function buildSmartAccountClient(ownerAddress: `0x${string}`, paymasterAddress: `0x${string}`) { + const publicClient = createPublicClient({ chain: sepolia, transport: http(RPC_URL) }); + + // walletClient wraps the user's signer (MetaMask, hardware wallet, etc.) + const walletClient = createWalletClient({ + account: ownerAddress, + chain: sepolia, + transport: custom(window.ethereum), + }); + + const pimlicoClient = createPimlicoClient({ + transport: http(PIMLICO_URL), + entryPoint: { address: entryPoint08Address, version: '0.8' }, + }); + + // Wraps the delegated EOA as an EIP-7702 smart account + const account = await to7702SimpleSmartAccount({ + client: publicClient, + owner: walletClient, + }); + + const smartAccountClient = createSmartAccountClient({ + account, + chain: sepolia, + bundlerTransport: http(PIMLICO_URL), + client: publicClient, + // PlatformPaymaster — validates on-chain, no off-chain signature needed + paymaster: { + async getPaymasterStubData() { + return { + paymaster: paymasterAddress, + paymasterData: '0x' as `0x${string}`, + paymasterVerificationGasLimit: 300_000n, + paymasterPostOpGasLimit: 150_000n, + isFinal: false, + }; + }, + async getPaymasterData() { + return { + paymaster: paymasterAddress, + paymasterData: '0x' as `0x${string}`, + paymasterVerificationGasLimit: 300_000n, + paymasterPostOpGasLimit: 150_000n, + }; + }, + }, + userOperation: { + estimateFeesPerGas: async () => { + const { fast } = await pimlicoClient.getUserOperationGasPrice(); + return { maxFeePerGas: fast.maxFeePerGas, maxPriorityFeePerGas: fast.maxPriorityFeePerGas }; + }, + }, + }); + + return { smartAccountClient, publicClient }; +} +``` + +:::note +The first time a user submits a UserOp their EOA is automatically delegated in the same bundle — no separate delegation transaction is needed when using `to7702SimpleSmartAccount`. +::: + +## Required environment variables + +| Variable | Description | +|---|---| +| `PRIVATE_KEY` | Platform owner private key (pays deployment gas) | +| `SEPOLIA_RPC_URL` | Sepolia RPC endpoint | +| `PIMLICO_API_KEY` | Pimlico bundler API key — free tier at [dashboard.pimlico.io](https://dashboard.pimlico.io) | +| `PAYMASTER_ADDRESS` | Deployed `PlatformPaymaster` clone address | diff --git a/sidebars.json b/sidebars.json index 0b0461e..e932bde 100755 --- a/sidebars.json +++ b/sidebars.json @@ -257,6 +257,11 @@ "migration-guide/migration-tr-v5", "migration-guide/migration-tt-cli-v5" ], + "Gasless (EIP-7702)": [ + "eip7702/overview", + "eip7702/setup", + "eip7702/gasless-operations" + ], "Community": ["community/contributing"], "Common Issues & Solutions": [ "common-issues/cors-error", From 3a88d4facc077a9a54ddf41cc96442dce4572ef7 Mon Sep 17 00:00:00 2001 From: Rishabh Singh Date: Thu, 9 Jul 2026 12:44:58 +0530 Subject: [PATCH 2/3] docs(eip7702): add Pimlico account setup guide and beta install notice Co-Authored-By: Claude Sonnet 4.6 --- docs/eip7702/setup.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/eip7702/setup.md b/docs/eip7702/setup.md index b1c5286..1c3850b 100644 --- a/docs/eip7702/setup.md +++ b/docs/eip7702/setup.md @@ -8,6 +8,41 @@ sidebar_label: Setup This page walks through one-time setup steps: deploying a PlatformPaymaster for your platform, whitelisting users, and building the `smartAccountClient` that all gasless SDK functions accept. +:::caution Beta +Install the beta release of `@trustvc/trustvc` to access the EIP-7702 gasless functions: + +```bash +npm install @trustvc/trustvc@beta permissionless viem +``` + +The gasless API is not available in the `latest` (`2.x`) release. +::: + +## 0. Get a Pimlico API key + +Pimlico is the bundler that submits UserOperations on behalf of users. A free account is sufficient for development and testing. + +1. Go to [dashboard.pimlico.io](https://dashboard.pimlico.io) and sign up (GitHub or email). +2. Create a new **API key** from the dashboard. +3. Add it to your `.env`: + +```env +PIMLICO_API_KEY=your_key_here +``` + +The bundler URL is constructed as: + +```text +https://api.pimlico.io/v2/{chainId}/rpc?apikey={PIMLICO_API_KEY} +``` + +| Network | chainId | +| --- | --- | +| Sepolia | `11155111` | +| Polygon Amoy | `80002` | + +Pimlico's free tier has no credit card requirement and is enough to run through this entire guide. + ## 1. Deploy a PlatformPaymaster Each platform (issuer) deploys its own `PlatformPaymaster` clone via `PlatformAccountFactory`. The clone is a cheap minimal proxy (~55 k gas) with its own state (owner, daily limit, authorized registries). From 5b83b4f6679f2ae9b5915cfe428cd26fbe592160 Mon Sep 17 00:00:00 2001 From: Rishabh Singh Date: Thu, 9 Jul 2026 13:32:18 +0530 Subject: [PATCH 3/3] docs(eip7702): update SDK install command to beta tag --- docs/eip7702/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/eip7702/overview.md b/docs/eip7702/overview.md index ed4bb80..824c892 100644 --- a/docs/eip7702/overview.md +++ b/docs/eip7702/overview.md @@ -74,7 +74,7 @@ PlatformPaymaster The `@trustvc/trustvc` SDK exposes all gasless functions under the `eip7702-functions` namespace. Install it once: ```bash -npm install @trustvc/trustvc +npm install @trustvc/trustvc@beta ``` Import any gasless function directly: