> For the complete documentation index, see [llms.txt](https://docs.greenowl.money/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.greenowl.money/smart-contracts/contracts/smartwalletfactory.md).

# SmartWalletFactory

## Overview

The **SmartWalletFactory** is a UUPS-upgradeable factory contract responsible for deploying deterministic SmartWallet instances using CREATE2. It enables AI agents and users to deploy multiple smart wallets per owner with predictable addresses, making wallet discovery and management efficient for MCP servers and frontend applications.

**Key responsibilities:**

* Deploy SmartWallet instances with deterministic addresses
* Track wallet ownership for registry and paymaster validation
* Manage wallet implementation upgrades (pull-based model)
* Enforce deployment limits and pausability for safety

**Design highlights:**

* **CREATE2 deterministic deployment** — wallet addresses are computable before deployment
* **Multi-wallet support** — each owner can deploy up to 50 wallets using different salts
* **Pull-based upgrades** — wallets upgrade themselves by calling the factory's `walletImplementation` registry
* **Pausable deployments** — factory owner can halt new wallet creation in emergencies
* **Ownership tracking** — maintains a registry of all wallets per owner for efficient lookup

***

## Architecture Context

The factory is designed to work seamlessly with ERC-4337 account abstraction:

1. **Bundler integration** — `getInitCode()` provides the exact bytes needed for UserOperation initialization
2. **EntryPoint compatibility** — wallets are deployed via EntryPoint's SenderCreator for gas efficiency
3. **Paymaster support** — `isValidWallet` mapping allows paymasters to verify wallet authenticity
4. **MCP integration** — predictable addresses enable MCP servers to compute wallet addresses client-side before deployment

***

## State Variables

### Constants

| Variable                | Type             | Description                                                   |
| ----------------------- | ---------------- | ------------------------------------------------------------- |
| `MAX_WALLETS_PER_OWNER` | `uint256`        | Maximum wallets per owner (50)                                |
| `ENTRY_POINT`           | `IEntryPoint`    | ERC-4337 EntryPoint contract (immutable)                      |
| `WALLET_IMPLEMENTATION` | `address`        | Base SmartWallet implementation (immutable)                   |
| `SENDER_CREATOR`        | `ISenderCreator` | EntryPoint's SenderCreator for CREATE2 deployment (immutable) |

### Mutable State

| Variable               | Type                       | Description                                             |
| ---------------------- | -------------------------- | ------------------------------------------------------- |
| `walletImplementation` | `address`                  | Current upgrade target for wallets (updatable by owner) |
| `isValidWallet`        | `mapping(address => bool)` | Registry of deployed wallets for validation             |
| `totalWallets`         | `uint256`                  | Total number of wallets deployed by this factory        |

### Internal Storage

| Variable        | Type                                           | Description                                      |
| --------------- | ---------------------------------------------- | ------------------------------------------------ |
| `_ownerWallets` | `mapping(address => EnumerableSet.AddressSet)` | All wallets per owner (for multi-wallet support) |

***

## Core Functions

### createWallet

Deploys a new SmartWallet instance with deterministic address.

```solidity
function createWallet(
    address walletOwner,
    address guardian,
    uint256 salt
) external whenNotPaused returns (address wallet)
```

**Parameters:**

| Name          | Type      | Description                                            |
| ------------- | --------- | ------------------------------------------------------ |
| `walletOwner` | `address` | Wallet owner address (ECDSA or P256 signer)            |
| `guardian`    | `address` | Optional initial guardian (use `address(0)` to skip)   |
| `salt`        | `uint256` | Additional salt for CREATE2 (for multi-wallet support) |

**Returns:**

| Name     | Type      | Description                |
| -------- | --------- | -------------------------- |
| `wallet` | `address` | Address of deployed wallet |

**Requirements:**

* Factory must not be paused
* Owner must not exceed `MAX_WALLETS_PER_OWNER` limit
* Uses CREATE2 for deterministic deployment via EntryPoint's SenderCreator

**Usage (MCP context):**

```typescript
// MCP tool deploys wallet for AI agent
const wallet = await factory.createWallet(
  agentOwnerAddress,  // Agent's signer address
  guardianAddress,    // Optional guardian
  0                   // First wallet (salt = 0)
);
```

***

### getWalletAddress

Computes the deterministic address of a wallet before deployment.

```solidity
function getWalletAddress(
    address walletOwner,
    address guardian,
    uint256 salt
) public view returns (address)
```

**Parameters:**

| Name          | Type      | Description              |
| ------------- | --------- | ------------------------ |
| `walletOwner` | `address` | Wallet owner address     |
| `guardian`    | `address` | Initial guardian address |
| `salt`        | `uint256` | Deployment salt          |

**Returns:**

| Name     | Type      | Description             |
| -------- | --------- | ----------------------- |
| `<none>` | `address` | Computed wallet address |

**Usage:** Critical for MCP servers to compute wallet addresses client-side without network calls.

***

### getInitCode

Returns ERC-4337 initCode for UserOperation deployment.

```solidity
function getInitCode(
    address walletOwner,
    address guardian,
    uint256 salt
) public view returns (bytes memory)
```

**Parameters:**

| Name          | Type      | Description              |
| ------------- | --------- | ------------------------ |
| `walletOwner` | `address` | Wallet owner address     |
| `guardian`    | `address` | Initial guardian address |
| `salt`        | `uint256` | Deployment salt          |

**Returns:**

| Name     | Type    | Description                                 |
| -------- | ------- | ------------------------------------------- |
| `<none>` | `bytes` | initCode bytes for `UserOperation.initCode` |

**Usage:**

```typescript
// Bundler uses this for first UserOperation (wallet deployment + execution)
const initCode = await factory.getInitCode(owner, guardian, salt);
const userOp = {
  sender: computedWalletAddress,
  initCode: initCode,  // Triggers deployment if sender doesn't exist
  // ... other fields
};
```

***

## View Functions

### getWalletsForOwner

Returns all wallet addresses for a given owner.

```solidity
function getWalletsForOwner(address walletOwner)
    external
    view
    returns (address[] memory)
```

**Parameters:**

| Name          | Type      | Description            |
| ------------- | --------- | ---------------------- |
| `walletOwner` | `address` | Owner address to query |

**Returns:**

| Name     | Type        | Description                                      |
| -------- | ----------- | ------------------------------------------------ |
| `<none>` | `address[]` | Array of wallet addresses owned by `walletOwner` |

**Usage:** Used by MCP servers and frontends to discover all wallets for an AI agent or user.

***

## Admin Functions

### setWalletImplementation

Updates the wallet implementation address for future upgrades.

```solidity
function setWalletImplementation(address newImplementation)
    external
    onlyOwner
```

**Parameters:**

| Name                | Type      | Description                            |
| ------------------- | --------- | -------------------------------------- |
| `newImplementation` | `address` | New SmartWallet implementation address |

**Access Control:** `onlyOwner`

**Note:** Wallets must individually call `upgradeToLatest()` to adopt the new implementation. This pull-based model prevents forced upgrades.

***

### pause

Pauses all wallet deployments.

```solidity
function pause() external onlyOwner
```

**Access Control:** `onlyOwner`

**Effect:** Prevents `createWallet()` calls until unpaused.

***

### unpause

Unpauses wallet deployments.

```solidity
function unpause() external onlyOwner
```

**Access Control:** `onlyOwner`

***

## Wallet Integration

### notifyOwnershipTransfer

Called by SmartWallet when ownership is transferred to update factory mappings.

```solidity
function notifyOwnershipTransfer(
    address previousOwner,
    address newOwner
) external
```

**Parameters:**

| Name            | Type      | Description           |
| --------------- | --------- | --------------------- |
| `previousOwner` | `address` | Previous wallet owner |
| `newOwner`      | `address` | New wallet owner      |

**Access Control:** Only callable by valid wallets deployed by this factory

**Note:** This callback maintains the `_ownerWallets` registry in O(1) time using EnumerableSet. It ensures `getWalletsForOwner()` remains accurate after ownership transfers.

***

## Utility Functions

### version

Returns the factory version number.

```solidity
function version() public pure virtual returns (uint256)
```

**Returns:**

| Name     | Type      | Description                             |
| -------- | --------- | --------------------------------------- |
| `<none>` | `uint256` | Factory version (1 for initial release) |

***

## Security Considerations

### Access Control

* **Factory owner** controls:
  * Wallet implementation upgrades via `setWalletImplementation()`
  * Deployment pausability via `pause()` / `unpause()`
  * Factory upgrades via UUPS `_authorizeUpgrade()`

### Deployment Limits

* **Per-owner limit:** Maximum 50 wallets per owner prevents abuse
* **Pausable:** Factory owner can halt deployments in emergencies

### Upgrade Model

* **Pull-based upgrades:** Wallets must explicitly call `upgradeToLatest()` — no forced upgrades
* **Implementation immutability:** `WALLET_IMPLEMENTATION` is immutable; only `walletImplementation` (upgrade target) is mutable

### Registry Integrity

* **Ownership tracking:** `notifyOwnershipTransfer()` keeps wallet-owner mappings accurate
* **Validation support:** `isValidWallet` mapping enables paymasters to verify wallet authenticity

***

## Integration Patterns

### MCP Server Integration

```typescript
// Compute wallet address before deployment
const walletAddress = await factory.getWalletAddress(owner, guardian, salt);

// Check if wallet exists
const code = await provider.getCode(walletAddress);
const exists = code !== "0x";

// Deploy if needed
if (!exists) {
  const initCode = await factory.getInitCode(owner, guardian, salt);
  // Submit UserOperation with initCode to bundler
}
```

### Multi-Wallet Management

```typescript
// Discover all wallets for an agent
const wallets = await factory.getWalletsForOwner(agentAddress);

// Deploy additional wallet with unique salt
const newWallet = await factory.createWallet(
  agentAddress,
  guardianAddress,
  wallets.length  // Use current count as salt
);
```

### Paymaster Validation

```solidity
// Paymaster checks wallet authenticity
require(
  factory.isValidWallet(userOp.sender),
  "Invalid wallet"
);
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.greenowl.money/smart-contracts/contracts/smartwalletfactory.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
