Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ERC: Paymaster Web Service Capability #360

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
417f757
add erc: paymaster service capability
lukasrosario Apr 4, 2024
5377892
fix name
lukasrosario Apr 4, 2024
6075b50
fix name again
lukasrosario Apr 4, 2024
e34591f
add flow diagrams
lukasrosario Apr 4, 2024
484ddd3
naming again maybe
lukasrosario Apr 4, 2024
6e64bef
name
lukasrosario Apr 4, 2024
441b6c4
add authors
lukasrosario Apr 4, 2024
94d5658
Update ERCS/erc-draft_pm_capability.md
lukasrosario Apr 5, 2024
8c81251
Update ERCS/erc-draft_pm_capability.md
lukasrosario Apr 5, 2024
f4e07c8
remove signature and paymasterAndData fields, add sponsor info
lukasrosario Apr 5, 2024
613305e
update description
lukasrosario Apr 5, 2024
0b26c72
context note
lukasrosario Apr 5, 2024
936d8c5
context note
lukasrosario Apr 5, 2024
71500ac
file names
lukasrosario Apr 5, 2024
02ee8be
sponsor example
lukasrosario Apr 5, 2024
76459c5
remove quotes
lukasrosario Apr 5, 2024
45e2fe1
add Kristof
lukasrosario Apr 5, 2024
2dc572b
update gas rationale wording
lukasrosario Apr 5, 2024
d90e25f
feedback
lukasrosario Apr 9, 2024
f9e15bf
change wording
lukasrosario Apr 9, 2024
3e0685a
remove signature from example
lukasrosario Apr 10, 2024
eac9c04
add note on signature
lukasrosario Apr 10, 2024
bf25878
Expand rationale to include known challenges with stub data
hazim-j Apr 13, 2024
4fb929b
fix grammar
hazim-j Apr 13, 2024
0221d65
Merge pull request #1 from hazim-j/paymaster-service-capability-ratio…
lukasrosario Apr 16, 2024
bd60be6
add Hazim, add note on chain id param
lukasrosario Apr 16, 2024
255a70b
update Hazim's handle
lukasrosario Apr 16, 2024
3ada65b
add gas values, typing
lukasrosario Apr 19, 2024
c3116ff
Merge branch 'master' into paymaster-service-capability
lukasrosario Apr 20, 2024
2e0d070
add note that apps must not assume paymaster is used
lukasrosario May 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
350 changes: 350 additions & 0 deletions ERCS/erc-7677.md
@@ -0,0 +1,350 @@
---
eip: 7677
title: Paymaster Web Service Capability
description: A way for apps to communicate with smart wallets about paymaster web services
author: Lukas Rosario (@lukasrosario), Dror Tirosh (@drortirosh), Wilson Cusack (@wilsoncusack), Kristof Gazso (@kristofgazso), Hazim Jumali (@hazim-j)
discussions-to: https://ethereum-magicians.org/t/erc-7677-paymaster-web-service-capability/19530
status: Draft
type: Standards Track
category: ERC
created: 2024-04-03
requires: 4337, 5792
---

## Abstract

With [EIP-5792](./eip-5792.md), apps can communicate with wallets about advanced features via capabilities. This proposal defines a capability that allows apps to request that [ERC-4337](./eip-4337.md) wallets communicate with a specified paymaster web service. To support this, we also define a standardized API for paymaster web services.

## Motivation

App developers want to start sponsoring their users' transactions using paymasters. Paymasters are commonly used via web services. However, there is currently no way for apps to tell wallets to communicate with a specific paymaster web service. Similarly, there is no standard for how wallets should communicate with these services. We need both a way for apps to tell wallets to communicate with a specific paymaster web service and a communication standard for wallets to do so.

## Specification

One new [EIP-5792](./eip-5792.md) wallet capability is defined. We also define a standard interface for paymaster web services as a prerequisite.

### Paymaster Web Service Interface

We define two JSON-RPC methods to be implemented by paymaster web services.

#### `pm_getPaymasterStubData`

Returns stub values to be used in paymaster-related fields of an unsigned user operation for gas estimation. Accepts an unsigned user operation, entrypoint address, chain id, and a context object. Paymaster service providers can define fields that app developers should use in the context object.

This method MAY return paymaster-specific gas values if applicable to the provided EntryPoint version. For example, if provided with EntryPoint v0.7, this method MAY return `paymasterVerificationGasLimit` and `paymasterPostOpGasLimit` values. The wallet SHOULD use these provided gas values when submitting the `UserOperation` to a bundler for gas estimation.

##### `pm_getPaymasterStubData` RPC Specification

Note that the user operation parameter does not include a signature, as the user signs after all other fields are populated.

```typescript
// [userOp, entryPoint, chainId, context]
type GetPaymasterStubDataParams = [
// Below is specific to Entrypoint v0.6 but this API can be used with other entrypoint versions too
{
sender: `0x${string}`;
nonce: `0x${string}`;
initCode: `0x${string}`;
callData: `0x${string}`;
callGasLimit: `0x${string}`;
verificationGasLimit: `0x${string}`;
preVerificationGas: `0x${string}`;
maxFeePerGas: `0x${string}`;
maxPriorityFeePerGas: `0x${string}`;
lukasrosario marked this conversation as resolved.
Show resolved Hide resolved
}, // userOp
`0x${string}`, // EntryPoint
`0x${string}`, // Chain ID
Record<string, any> // Context
];

type GetPaymasterStubDataResult = {
paymaster?: string // Paymaster address (entrypoint v0.7)
paymasterData?: string; // Paymaster data (entrypoint v0.7)
paymasterVerificationGasLimit?: `0x${string}`; // Paymaster validation gas (entrypoint v0.7)
paymasterPostOpGasLimit?: `0x${string}`; // Paymaster post-op gas (entrypoint v0.7)
paymasterAndData?: string; // Paymaster and data (entrypoint v0.6)
}
```

###### `pm_getPaymasterStubData` Example Parameters

```json
[
{
"sender": "0x...",
"nonce": "0x...",
"initCode": "0x",
"callData": "0x...",
"callGasLimit": "0x...",
"verificationGasLimit": "0x...",
"preVerificationGas": "0x...",
"maxFeePerGas": "0x...",
"maxPriorityFeePerGas": "0x...",
},
"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
"0x2105",
{
// Illustrative context field. These should be defined by service providers.
"policyId": "962b252c-a726-4a37-8d86-333ce0a07299"
}
]
```

###### `pm_getPaymasterStubData` Example Return Value

Paymaster services MUST detect which entrypoint version the account is using and return the correct fields.

For example, if using entrypoint v0.6:

```json
{
"paymasterAndData": "0x..."
}
```

If using entrypoint v0.7:

```json
{
"paymaster": "0x...",
"paymasterData": "0x..."
}
```

If using entrypoint v0.7, with paymaster gas estimates:

```json
{
"paymaster": "0x...",
"paymasterData": "0x...",
"paymasterVerificationGasLimit": "0x...",
"paymasterPostOpGasLimit": "0x..."
}
```

#### `pm_getPaymasterData`

Returns values to be used in paymaster-related fields of a signed user operation. These are not stub values and will be used during user operation submission to a bundler. Similar to `pm_getPaymasterStubData`, accepts an unsigned user operation, entrypoint address, chain id, and a context object.

This method also returns a `sponsor` object with `name` and `icon` fields. The `name` field is the name of the party sponsoring the transaction, and the `icon` field is a URI pointing to an image. Wallet developers MAY choose to display sponsor information to users. The `icon` string MUST be a data URI as defined in [RFC-2397]. The image SHOULD be a square with 96x96px minimum resolution. The image format is RECOMMENDED to be either lossless or vector based such as PNG, WebP or SVG to make the image easy to render on the wallet. Since SVG images can execute Javascript, wallets MUST render SVG images using the `<img>` tag to ensure no untrusted Javascript execution can occur.

##### `pm_getPaymasterData` RPC Specification

Note that the user operation parameter does not include a signature, as the user signs after all other fields are populated.

```typescript
// [userOp, entryPoint, chainId, context]
type GetPaymasterDataParams = [
// Below is specific to Entrypoint v0.6 but this API can be used with other entrypoint versions too
{
sender: `0x${string}`;
nonce: `0x${string}`;
initCode: `0x${string}`;
callData: `0x${string}`;
callGasLimit: `0x${string}`;
verificationGasLimit: `0x${string}`;
preVerificationGas: `0x${string}`;
maxFeePerGas: `0x${string}`;
maxPriorityFeePerGas: `0x${string}`;
lukasrosario marked this conversation as resolved.
Show resolved Hide resolved
}, // userOp
`0x${string}`, // Entrypoint
`0x${string}`, // Chain ID
Record<string, any> // Context
];

type GetPaymasterDataResult = {
sponsor?: { name: string; icon: string } // Sponsor info
paymaster?: string // Paymaster address (entrypoint v0.7)
paymasterData?: string; // Paymaster data (entrypoint v0.7)
paymasterAndData?: string; // Paymaster and data (entrypoint v0.6)
}
```

###### `pm_getPaymasterData` Example Parameters

```json
[
{
"sender": "0x...",
"nonce": "0x...",
"initCode": "0x",
"callData": "0x...",
"callGasLimit": "0x...",
"verificationGasLimit": "0x...",
"preVerificationGas": "0x...",
"maxFeePerGas": "0x...",
"maxPriorityFeePerGas": "0x...",
},
"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
"0x2105",
{
// Illustrative context field. These should be defined by service providers.
"policyId": "962b252c-a726-4a37-8d86-333ce0a07299"
}
]
```

###### `pm_getPaymasterData` Example Return Value

Paymaster services MUST detect which entrypoint version the account is using and return the correct fields.

For example, if using entrypoint v0.6:

```json
{
"sponsor": {
"name": "My App",
"icon": "https://..."
},
"paymasterAndData": "0x..."
}
```

If using entrypoint v0.7:
lukasrosario marked this conversation as resolved.
Show resolved Hide resolved

```json
{
"sponsor": {
"name": "My App",
"icon": "https://..."
},
"paymaster": "0x...",
"paymasterData": "0x..."
}
```

### `paymasterService` Capability

The `paymasterService` capability is implemented by both apps and wallets.

#### App Implementation

Apps need to give wallets a paymaster service URL they can make the above RPC calls to. They can do this using the `paymasterService` capability as part of an [EIP-5792](./eip-5792.md) `wallet_sendCalls` call.

##### `wallet_sendCalls` Paymaster Capability Specification

```typescript
type PaymasterCapabilityParams = {
url: string;
context: Record<string, any>;
}
```

###### `wallet_sendCalls` Example Parameters

```json
[
{
"version": "1.0",
"chainId": "0x01",
"from": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"calls": [
{
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"value": "0x9184e72a",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
},
{
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"value": "0x182183",
"data": "0xfbadbaf01"
}
],
"capabilities": {
"paymasterService": {
"url": "https://...",
"context": {
"policyId": "962b252c-a726-4a37-8d86-333ce0a07299"
}
}
}
}
]
```

The wallet will then make the above paymaster RPC calls to the URL specified in the `paymasterService` capability field.

#### Wallet Implementation

To conform to this specification, smart wallets that wish to leverage app-sponsored transactions:
1. MUST indicate to apps that they can communicate with paymaster web services via their response to an [EIP-5792](./eip-5792.md) `wallet_getCapabilities` call.
2. SHOULD make calls to and use the values returned by the paymaster service specified in the capabilities field of an [EIP-5792](./eip-5792.md) `wallet_sendCalls` call. An example of an exception is a wallet that allows users to select a paymaster provided by the wallet. Since there might be cases in which the provided paymaster is ultimately not used—either due to service failure or due to a user selecting a different, wallet-provided paymaster—applications MUST NOT assume that the paymaster it provides to a wallet is the entity that pays for transaction fees.

##### `wallet_getCapabilities` Response Specification

```typescript
type PaymasterServiceCapability = {
supported: boolean;
}
```

###### `wallet_getCapabilities` Example Response

```json
{
"0x2105": {
"paymasterService": {
"supported": true
},
},
"0x14A34": {
"paymasterService": {
"supported": true
}
}
}
```

Below is a diagram illustrating the full `wallet_sendCalls` flow, including how a wallet might implement the interaction.

![flow](../assets/eip-7677/0.png)

## Rationale

### Gas Estimation

The current loose standard for paymaster services is to implement `pm_sponsorUserOperation`. This method returns values for paymaster-related user operation fields and updated gas values. The problem with this method is that paymaster service providers have different ways of estimating gas, which results in different estimated gas values. Sometimes these estimates can be insufficient. As a result we believe it’s better to leave gas estimation up to the wallet, as the wallet has more context on how user operations will get submitted (e.g. which bundler they will get submitted to). Then wallets can ask paymaster services to sponsor given the estimates defined by the wallet.

The above reason is also why we specify that the `pm_getPaymasterStubData` method MAY also return paymaster-specific gas estimates. I.e., bundlers are prone to insufficiently estimating the paymaster-specific gas values, and the paymaster servies themselves are ultimately better equipped to provide them.

### Chain ID Parameter

Currently, paymaster service providers typically provide developers with a URL per chain. That is, paymaster service URLs are not typically multichain. So why do we need a chain ID parameter? We recognize that we must specify some constraint so that wallets can communicate with paymaster services about which chain their requests are for. As we see it, there are two options:

1. Formalize the current loose standard and require that paymaster service URLs are 1:1 with chains.
2. Require a chain ID parameter as part of paymaster service requests.

We feel that option (2) is the better abstraction here. This allows service providers to offer multichain URLs if they wish at essentially no downside to providers who offer a URL per chain. Providers who offer a URL per chain would just need to accept an additional parameter that they can ignore. When an app developer who uses a URL-per-chain provider wants to submit a request to a different chain, they can just swap out the URL accordingly.

### Challenges With Stub Data

Enabling a workflow with greater flexibility in gas estimations will nonetheless come with some known challenges that paymaster services must be aware of in order to ensure reliable gas estimates are generated during the process.

#### `preVerificationGas`

The `preVerificationGas` value is largely influenced by the size of the user operation and it's ratio of zero to non-zero bytes. This can cause a scenario where `pm_getPaymasterStubData` returns values that results in upstream gas estimations to derive a lower `preVerificationGas` compared to what `pm_getPaymasterData` would require. If this occurs then bundlers will return an insufficient `preVerificationGas` error during `eth_sendUserOperation`.

To avoid this scenario, a paymaster service MUST return stub data that:

1. Is of the same length as the final data.
2. Has an amount of zero bytes (`0x00`) that is less than or equal to the final data.

#### Consistent Code Paths

In the naive case, a stub value of repeating non-zero bytes (e.g. `0x01`) that is of the same length as the final value will generate a usable `preVerificationGas`. Although this would immediately result in a gas estimation error given that the simulation will likely revert due to an invalid paymaster data.

In a more realistic case, a valid stub can result in a successful simulation but still return insufficient gas limits. This can occur if the stub data causes `validatePaymasterUserOp` or `postOp` functions to simulate a different code path compared to the final value. For example, if the simulated code was to return early, the estimated gas limits would be less than expected which would cause upstream `out of gas` errors once a user operation is submitted to the bundler.

Therefore, a paymaster service MUST also return a stub that can result in a simulation executing the same code path compared to what is expected of the final user operation.

## Security Considerations

The URLs paymaster service providers give to app developers commonly have API keys in them. App developers might not want to pass these API keys along to wallets. To remedy this, we recommend that app developers provide a URL to their app's backend, which can then proxy calls to paymaster services. Below is a modified diagram of what this flow might look like.
lukasrosario marked this conversation as resolved.
Show resolved Hide resolved

![flowWithAPI](../assets/eip-7677/0.png)

This flow would allow developers to keep their paymaster service API keys secret. Developers might also want to do additional simulation / validation in their backends to ensure they are sponsoring a transaction they want to sponsor.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
Binary file added assets/erc-7677/0.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/erc-7677/1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.