EIP-7702

Ink’s public EIP-7702 paymaster is live on EntryPoint v0.8. Use the SDK’s INK_PUBLIC_PAYMASTER_V08 deployment metadata; the default INK_PUBLIC_PAYMASTER constant remains pinned to EntryPoint v0.7.

EIP-7702 lets an EOA behave like a smart account by authorizing a delegate implementation. The paymaster supplies native ETH from its EntryPoint deposit and separately charges the EOA in USDC. USDC does not become Ink’s protocol gas token.

Live deployment

FieldValue
NetworkInk Mainnet (57073)
SDK@hellomoon/ink-paymaster v0.2.3 or later
SDK deploymentINK_PUBLIC_PAYMASTER_V08
EntryPoint v0.80x4337084D9E255Ff0702461CF8895CE9E3b5Ff108
Paymaster0xE361E63515109BFDC4c32EfC4d2e0ede4d4744D8
Simple7702 delegate0xe6Cae83BdE06E4c305530e199D7217f42808555B
Reimbursement tokenUSDC
Quote version3

Use the exported constants instead of copying these addresses into application code.

Before the first operation

The EOA must:

  1. hold enough native ETH to establish its USDC approval;
  2. hold enough USDC for the application call and gas reimbursement; and
  3. approve INK_PUBLIC_PAYMASTER_V08.paymaster to spend a finite USDC amount.

The public paymaster cannot pay for its own approval. Send that approval with ordinary gas before requesting a prepaid operation.

Create the EIP-7702 account

import { createPublicClient, defineChain, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import {
  createBundlerClient,
  toSimple7702SmartAccount,
} from "viem/account-abstraction";
import {
  createInkPublicPaymasterClient,
  createInkViemPaymaster,
  INK_PUBLIC_PAYMASTER_V08,
  INK_SIMPLE_7702_DELEGATE,
} from "@hellomoon/ink-paymaster";
 
const inkRpcUrl = process.env.INK_RPC_URL!;
const owner = privateKeyToAccount(process.env.OWNER_PRIVATE_KEY! as `0x${string}`);
const ink = defineChain({
  id: INK_PUBLIC_PAYMASTER_V08.chainId,
  name: INK_PUBLIC_PAYMASTER_V08.chainName,
  nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
  rpcUrls: { default: { http: [inkRpcUrl] } },
});
const publicClient = createPublicClient({
  chain: ink,
  transport: http(inkRpcUrl),
});
const account = await toSimple7702SmartAccount({
  client: publicClient,
  entryPoint: "0.8",
  implementation: INK_SIMPLE_7702_DELEGATE,
  owner,
});
const service = createInkPublicPaymasterClient({
  deployment: INK_PUBLIC_PAYMASTER_V08,
});

service.bundlerUrl points to the versioned EntryPoint v0.8 Alto endpoint. Alto is the ERC-4337 bundler; the separate paymaster contract supplies native gas through EntryPoint.

Send the first prepaid operation

Viem does not pass its EIP-7702 authorization into the paymaster hook. Supply the delegate in paymasterContext, then sign and pass the authorization to sendUserOperation explicitly.

const maxTokenCost = 100_000n;
const bundler = createBundlerClient({
  account,
  chain: ink,
  client: publicClient,
  transport: http(service.bundlerUrl),
  paymaster: createInkViemPaymaster(service),
  paymasterContext: {
    token: "USDC",
    maxTokenCost,
    idempotencyKey: "checkout-order-123",
    eip7702Delegate: INK_SIMPLE_7702_DELEGATE,
  },
});
 
const authorization = await owner.signAuthorization({
  address: INK_SIMPLE_7702_DELEGATE,
  chainId: ink.id,
  nonce: await publicClient.getTransactionCount({
    address: owner.address,
    blockTag: "pending",
  }),
});
 
const userOperationHash = await bundler.sendUserOperation({
  authorization,
  calls: [{ to: destination, value: 0n, data: calldata }],
});
const receipt = await bundler.waitForUserOperationReceipt({
  hash: userOperationHash,
});
if (!receipt.success) throw new Error("EIP-7702 operation reverted");

For an already delegated EOA, keep supplying eip7702Delegate in paymasterContext. The quote remains bound to the delegate installed on the sender even when a new authorization is unnecessary.

Safety checks

Quote version 3 signs the expected delegate address. The paymaster verifies the sender’s EIP-7702 code designator onchain. The SDK also rejects:

  • an EIP-7702 marker without paymasterContext.eip7702Delegate;
  • an EIP-7702 operation configured against EntryPoint v0.7;
  • a v0.8 deployment that reports quote version 2; and
  • a quote whose delegate differs from the requested or installed delegate.

Keep the account, UserOperation encoding, SDK deployment, paymaster, Alto, and EntryPoint on the same version.

Made with 💜 by the Ink team