> ## Documentation Index
> Fetch the complete documentation index at: https://docs.portalhq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Sign a user operation

> Sign an ERC-4337 UserOperation using your MPC key without broadcasting it.

The `eth_signUserOperation` method allows you to sign an [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) UserOperation using your client's MPC key without broadcasting it to the network. The signed UserOperation can then be submitted through a separate backend such as [Pimlico](https://www.pimlico.io/) or a custom bundler endpoint.

<Warning>
  This method requires your client to be created with [Account Abstraction](../../../resources/account-abstraction) enabled (`isAccountAbstracted: true`). Non-AA clients will receive a `METHOD_UNSUPPORTED` error.
</Warning>

## Prerequisites

Before using `eth_signUserOperation`, ensure that:

1. Your organization has Account Abstraction enabled. See the [Account Abstraction guide](../../../resources/account-abstraction) for setup instructions.
2. Your client was created with `isAccountAbstracted: true` via the [Create a new client endpoint](../../../apis/custodian/reference#create-a-new-client).
3. Your client has a wallet created and backed up.

## Signing a UserOperation

Use the `request` method with the `eth_signUserOperation` RPC method. The params array takes a single object with standard Ethereum transaction fields.

```dart theme={null}
import 'package:portal_flutter/portal_flutter.dart';

final portal = Portal();

// Sign a UserOperation on Sepolia testnet
final result = await portal.request(
  chainId: 'eip155:11155111',
  method: 'eth_signUserOperation',
  params: [
    {
      'to': '0xRecipientAddress',
      'value': '0x0',
      'data': '0x',
    }
  ],
);

if (result.error != null) {
  print('Error: ${result.error}');
} else {
  print('Signed UserOp: ${result.result}');
  // result.result contains a hex-encoded signed UserOperation JSON
}
```

<Note>
  The `chainId` must be a [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) compliant Chain ID for a [supported Account Abstraction network](../../../resources/account-abstraction#supported-networks).
</Note>

## Transaction Parameters

The params object supports the following fields:

| Parameter              | Type     | Required | Description                                 |
| ---------------------- | -------- | -------- | ------------------------------------------- |
| `to`                   | `String` | Yes      | The recipient or contract address           |
| `value`                | `String` | No       | Value in wei (hex-encoded)                  |
| `data`                 | `String` | No       | Calldata (hex-encoded)                      |
| `gas`                  | `String` | No       | Gas limit (hex-encoded)                     |
| `maxFeePerGas`         | `String` | No       | Max fee per gas for EIP-1559 (hex-encoded)  |
| `maxPriorityFeePerGas` | `String` | No       | Max priority fee for EIP-1559 (hex-encoded) |
| `nonce`                | `String` | No       | Transaction nonce (hex-encoded)             |

## Response

The method returns a `PortalProviderResponse` where `result` is a hex-encoded JSON string containing the signed UserOperation. You can decode this result and submit it to a bundler of your choice.

```dart theme={null}
import 'package:portal_flutter/portal_flutter.dart';

final portal = Portal();

final result = await portal.request(
  chainId: 'eip155:11155111',
  method: 'eth_signUserOperation',
  params: [
    {
      'to': '0xRecipientAddress',
      'value': '0xDE0B6B3A7640000', // 1 ETH in wei
      'data': '0x',
    }
  ],
);

if (result.error != null) {
  throw Exception('Failed to sign UserOp: ${result.error}');
}

// The signed UserOperation is a hex-encoded JSON string
final signedUserOp = result.result;
print('Signed UserOperation: $signedUserOp');

// Decode the hex string and submit to your bundler
// e.g., send signedUserOp to Pimlico or your custom bundler endpoint
```

## EIP-1559 Gas Parameters

You can specify EIP-1559 gas parameters for finer control over fees:

```dart theme={null}
final result = await portal.request(
  chainId: 'eip155:11155111',
  method: 'eth_signUserOperation',
  params: [
    {
      'to': '0xRecipientAddress',
      'value': '0x0',
      'data': '0x',
      'maxFeePerGas': '0x3B9ACA00',        // 1 Gwei
      'maxPriorityFeePerGas': '0x3B9ACA00', // 1 Gwei
    }
  ],
);
```

## Error Handling

| Error                | Description                                          |
| -------------------- | ---------------------------------------------------- |
| `METHOD_UNSUPPORTED` | The client does not have Account Abstraction enabled |
| `NOT_INITIALIZED`    | Portal was not initialized                           |
| `RPC_ERROR`          | The RPC call returned an error                       |

```dart theme={null}
try {
  final result = await portal.request(
    chainId: 'eip155:11155111',
    method: 'eth_signUserOperation',
    params: [
      {
        'to': '0xRecipientAddress',
        'value': '0x0',
        'data': '0x',
      }
    ],
  );

  if (result.error != null) {
    print('Provider error: ${result.error}');
    return;
  }

  print('Signed UserOp: ${result.result}');
} on PortalException catch (e) {
  print('Portal error: ${e.message}');
}
```

**Related Documentation**

* [request function reference](../reference/request)
* [eth\_signUserOperation reference](../reference/eth_signuseroperation)
* [Account Abstraction guide](../../../resources/account-abstraction)
* [Sign a transaction guide](./sign-a-transaction)
