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

# Account Abstraction

> Gasless and batched EVM transactions on iOS using Alchemy smart accounts backed by Para

The Swift SDK can spin up an Alchemy smart account for any EVM wallet your user holds. The Para wallet signs; the smart account is what shows up on-chain. You get gas sponsorship through Alchemy's Gas Manager and atomic batched calls through the Account Kit.

<Note>
  Only Alchemy (EIP-4337) is wired through the native bridge today. ZeroDev, Pimlico, and the other providers already available on web and React Native are on the roadmap for iOS.
</Note>

## Setup

1. Create an [Alchemy account](https://dashboard.alchemy.com/signup), grab your **API key**, and create a Gas Manager **policy** for the chain you're targeting. The policy ID is what tells the paymaster to sponsor gas.

2. Stash the values wherever you keep other credentials. A plain `Config` struct works:

```swift theme={null}
enum AlchemyConfig {
    static let apiKey = "YOUR_ALCHEMY_API_KEY"
    static let gasPolicyId = "YOUR_GAS_POLICY_ID"
    static let sepoliaChainId = 11155111
}
```

You don't need to add a package. `ParaSwift` already knows how to reach `@getpara/aa-alchemy` through the bridge.

## Usage

Create the smart account, then send a gasless transaction with it:

```swift theme={null}
import ParaSwift

// `paraManager` is your authenticated ParaManager instance
let info = try await paraManager.createSmartAccount(
    apiKey: AlchemyConfig.apiKey,
    chainId: AlchemyConfig.sepoliaChainId,
    gasPolicyId: AlchemyConfig.gasPolicyId
)
print("Smart account:", info.smartAccountAddress)

// Zero-value tx to the burn address, paid for by the paymaster.
let receipt = try await paraManager.sendSmartAccountTransaction(
    smartAccountAddress: info.smartAccountAddress,
    chainId: AlchemyConfig.sepoliaChainId,
    to: "0x000000000000000000000000000000000000dEaD"
)
print("tx:", receipt.transactionHash, "status:", receipt.status)
```

Heads up on timing: UserOp inclusion on a public chain usually lands in 30 to 90 seconds, and the call blocks until it does. `ParaWebView` defaults its request timeout to 120s for this reason. Pass a shorter value to `ParaWebView.init` if you'd rather bail earlier.

### Batched transactions

One UserOp, multiple calls, one receipt. Use it for approve + swap, approve + transfer, or anything that should succeed or fail together:

```swift theme={null}
let batchReceipt = try await paraManager.sendSmartAccountBatchTransaction(
    smartAccountAddress: info.smartAccountAddress,
    chainId: AlchemyConfig.sepoliaChainId,
    calls: [
        SmartAccountCall(to: "0xRecipientA", value: "10000000000000000"), // 0.01 ETH
        SmartAccountCall(to: "0xRecipientB", data: "0xEncodedCallData")
    ]
)
```

### Error handling

Provider failures come back with a `SmartAccountErrorCode` from `@getpara/core-sdk`. The ones you're most likely to see:

* `PROVIDER_RATE_LIMITED`: back off and retry.
* `SPONSORSHIP_DENIED`: the gas policy rejected this UserOp. Check the Alchemy dashboard.
* `TRANSACTION_REVERTED`: the target contract reverted at execution time.
* `MISSING_ACCOUNT_ADDRESS`: you called `sendSmartAccountTransaction` before `createSmartAccount` for this chain + address.

Errors surface as `ParaError.bridgeError` and keep the provider's original message. If a permissions policy blocks the tx, the call throws `ParaError.transactionDenied(pendingTransactionId:transactionReviewUrl:)` and fires `setTransactionReviewHandler` if you've registered one. Same pattern as `signTransaction`.

## What gets returned

`createSmartAccount` returns a `SmartAccountInfo`:

```swift theme={null}
struct SmartAccountInfo {
    let smartAccountAddress: String
    let mode: String       // "4337"
    let provider: String   // "ALCHEMY"
    let chainId: Int
}
```

`sendSmartAccountTransaction` and `sendSmartAccountBatchTransaction` return an `AATransactionReceipt`:

```swift theme={null}
struct AATransactionReceipt {
    let transactionHash: String
    let blockHash: String
    let blockNumber: String       // uint256, decimal string
    let from: String
    let to: String?
    let status: String            // "success" or "reverted"
    let gasUsed: String
    let effectiveGasPrice: String
}
```

BigInt fields arrive as decimal strings so you don't lose `uint256` precision across the bridge.

## Reference

Full working implementation: [`examples-hub/mobile/with-swift/example/SmartAccount/SmartAccountView.swift`](https://github.com/getpara/examples-hub/tree/3.0.0/mobile/with-swift/example/SmartAccount).
