# RPCs for Session Keys and the Wallet Server Model
Many teams across the industry are working on various pieces of the session key flow. Notably, we have:
- Session-key compatible account contracts from various AA stack providers.
- ERC-7715 "Grant Permissions from Wallets," which defines RPC methods that enable app developers to create and revoke session keys.
- ERC-7679 "UserOperation Builder," which defines a contract interface for account providers to implement to put how they encode user operations onchain.
At a high level, app developers who wish to use session keys are currently expected to:
1. Generate a key pair to use as a session key.
2. Use the ERC-7715 `wallet_grantPermissions` RPC to turn the generated key pair into a session key for a user's account.
3. Use the account's provided ERC-7679 "UserOperation Builder" contract (provided in the response to the `wallet_grantPermissions` request), along with the app developer's own bundler and paymaster setup to construct and submit a user operation.
One of our guiding principles as we've built out new functionality for the Coinbase Smart Wallet is "smarter wallets, dumber apps." With this principle in mind, we've taken a slightly different approach to building session keys that replaces the above third step with RPC methods that, similar to EIP-5792 methods, abstract away the details of account implementations.
## Overview
```mermaid
sequenceDiagram
autonumber
participant App
participant Provider
participant Wallet
participant Bundler
App ->> App: Generate session key pair
App ->> Provider: wallet_grantPermissions({..., sessionKeyPublicKey})
Provider ->> Wallet: wallet_grantPermissions({..., sessionKeyPublicKey})
Wallet ->> Wallet: User signs
Wallet ->> Provider: permissionsContext
Provider ->> App: permissionsContext
App ->> Provider: wallet_prepareCalls({calls, capabilities: {permissionsContext}})
Provider ->> Wallet: wallet_prepareCalls({calls, capabilities: {permissionsContext}})
Wallet --> Bundler: Prepare calls (construct userOp)
Wallet ->> Provider: {preparedCalls, signatureRequest, context}
Provider ->> App: {preparedCalls, signatureRequest, context}
App ->> App: Signs signatureRequest with session key
App ->> Provider: wallet_sendPreparedCalls({preparedCalls, signature, context})
Provider ->> Wallet: wallet_sendPreparedCalls({preparedCalls, signature, context})
Wallet ->> Bundler: eth_sendUserOperation
Bundler ->> Wallet: userOp hash
Wallet ->> Provider: callsId
Provider ->> App: callsId
```
Starting at step 7, the above diagram details our proposed alternative to app developers constructing and submitting user operations themselves with ERC-7679. Specifically, we propose two new RPC methods:
- `wallet_prepareCalls`
- Accepts an EIP-5792 `wallet_sendCalls` request.
- Responds with the prepared calls (in the case of Coinbase Smart Wallet, a v0.6 user operation), some context, and a signature request.
- `wallet_sendPreparedCalls`
- Accepts prepared calls, a signature, and the context returned from `wallet_prepareCalls` if present.
- Returns an EIP-5792 calls ID.
## Specifications
### `wallet_prepareCalls`
Accepts an EIP-5792 `wallet_sendCalls` request, and returns the prepared calls according to the account's implementation.
#### Parameters
```typescript!
type PrepareCallsParams = [{
from: `0x${string}`
chainId: `0x${string}`
calls: {
to: `0x${string}`
data: `0x${string}`
value: `0x${string}`
}[];
capabilities: Record<string, any>
}]
```
##### Example Parameters
```typescript!
wallet_prepareCalls([{
from: '0x...',
chainId: '0x...',
calls: [{
to: '0x...'
data: '0x...'
value: '0x...'
}],
capabilities: {
permissions: {
context: '0x...' // Importantly for session keys, wallets will likely need the ERC-7715 permissions context for userOp construction
}
}
}])
```
#### Return Value
```typescript!
type PrepareCallsReturnValue = [{
preparedCalls: {
type: string
data: any
chainId: `0x${string}`
}
signatureRequest: {
hash: `0x${string}`
}
context: `0x${string}`
}]
```
##### Example Return Value
```typescript!
[{
preparedCalls: {
type: 'user-operation-v06', type
data: { // ...userOp
sender: '0x...',
...
},
chainId: '0x01'
},
signatureRequest: {
hash: '0x...' // user op hash in our case
},
context: '0x...' // params.capabilities.permissions.context in our case
}]
```
After calling `wallet_prepareCalls`, app developers are expected to sign the hash provided in the `signatureRequest` field and submit the prepared and signed calls back to the wallet using the second RPC method, `wallet_sendPreparedCalls`.
### `wallet_sendPreparedCalls`
Accepts prepared calls from the response to a `wallet_prepareCalls` request along with a signature, and returns an EIP-5792 call bundle ID.
#### Parameters
```typescript!
type SendPreparedCallsParams = [{
preparedCalls: {
type: string
data: any
chainId: `0x${string}`
}
signature: Hex;
context: Hex;
}]
```
##### Example Parameters
```typescript!
wallet_sendPreparedCalls([{
preparedCalls: { // Same as response to wallet_prepareCalls
type: 'user-operation-v06',
data: { // ...userOp
sender: '0x...',
...
},
chainId: '0x01'
}
signature: '0x...', // Session key signature
context: '0x...', // Same as response to wallet_prepareCalls
}])
```
#### Return Value
```typescript!
type SendPreparedCallsReturnValue = string
```
##### Example Return Value
```typescript!
'0x...'
```
The `wallet_sendPreparedCalls` RPC responds with an EIP-5792 call bundle identifier, so apps that already use `wallet_sendCalls` to submit calls to the wallet popup can continue to use `wallet_getCallsStatus` to get the status of submitted calls.
## The Wallet Server Model
While reading this you might have wondered why or how an app developer would use `wallet_` namespaced RPCs when the point of session keys is to bypass the wallet popup / extension / app. This is where the wallet server comes in.

The wallet server is a complementary backend that an EIP-1193 provider routes specific requests (such as `wallet_prepareCalls` and `wallet_sendPreparedCalls`) to.
With the wallet server model in mind, a more accurate representation of the flow proposed looks likes the following:
```mermaid
sequenceDiagram
autonumber
participant App
participant Provider
box Wallet
participant Wallet Frontend
participant Wallet Server
end
participant Bundler
App ->> App: Generate session key pair
App ->> Provider: wallet_grantPermissions({..., sessionKeyPublicKey})
Provider ->> Wallet Frontend: wallet_grantPermissions({..., sessionKeyPublicKey})
Wallet Frontend ->> Wallet Frontend: User signs
Wallet Frontend ->> Provider: permissionsContext
Provider ->> App: permissionsContext
App ->> Provider: wallet_prepareCalls({calls, capabilities: {permissionsContext}})
Provider ->> Wallet Server: wallet_prepareCalls({calls, capabilities: {permissionsContext}})
Wallet Server --> Bundler: Prepare calls (construct userOp)
Wallet Server ->> Provider: {preparedCalls, signatureRequest, context}
Provider ->> App: {preparedCalls, signatureRequest, context}
App ->> App: Signs signatureRequest with session key
App ->> Provider: wallet_sendPreparedCalls({preparedCalls, signature, context})
Provider ->> Wallet Server: wallet_sendPreparedCalls({preparedCalls, signature, context})
Wallet Server ->> Bundler: eth_sendUserOperation
Bundler ->> Wallet Server: userOp hash
Wallet Server ->> Provider: callsId
Provider ->> App: callsId
```
## What's Next
This is all still a work in progress, and we are eager to hear feedback. That said, we have a working testnet prototype of this proposal (see docs [here](https://www.smartwallet.dev/guides/session-keys)) and are actively working on getting this ready for mainnet.