# UserClient

> Testing helper that simulates a user's wallet for signing operations.

`UserClient` holds a private key and provides signing methods for both orders and Safe transactions. In production, replace `UserClient` with actual wallet integration (MetaMask, WalletConnect, etc.).

## Import

```python
from opinion_clob_sdk.user_client import UserClient
```

## Create a Random User

```python
user = UserClient.create_random()
print(user.address)  # Random wallet address
```

## Create from Private Key

```python
user = UserClient("0xYourPrivateKey...")
print(user.address)  # Derived wallet address
```

## File Persistence

Load a user from a JSON file, or create a new one and save it:

```python
# Load or create (saves to file if new)
user = UserClient.load_or_create(".test_user.json")

# Load from existing file (raises FileNotFoundError if missing)
user = UserClient.load_from_file(".test_user.json")

# Save current user to file
user.save_to_file(".test_user.json")
```

The JSON file format:

```json
{
  "address": "0x1234...",
  "private_key": "0xabcd..."
}
```

## Sign Safe Transactions

Use `sign_typed_data()` for Safe transaction signing (Enable Trading, Split, Merge, Redeem, Withdraw):

```python
tx_result = builder.build_enable_trading_tx(safe_address)
signature = user.sign_typed_data(tx_result["eip712_data"])
```

## Sign Orders

Use `sign_hash()` for order signing. This signs the order struct hash directly:

```python
build_result = builder.build_order_for_signing(...)
signature = user.sign_hash(build_result["struct_hash"])
```

## Properties

| Property  | Type | Description                  |
| --------- | ---- | ---------------------------- |
| `address` | str  | Checksummed Ethereum address |

## Notes

* `UserClient` is a **testing helper only**. Do not use it in production with real user funds.
* Order signing uses `sign_hash()` (signs raw hash), while Safe TX signing uses `sign_typed_data()` (signs EIP-712 structured data). These are different operations and are not interchangeable.
* The `sign_hash()` method calls `Account._sign_hash()` internally, matching the original SDK signing behavior.
