> ## 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

export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
  const [isHovered, setIsHovered] = useState(false);
  const handleClick = e => {
    e.preventDefault();
    if (newTab) {
      window.open(href, '_blank', 'noopener,noreferrer');
    } else {
      window.location.href = href;
    }
  };
  return <div className={`not-prose relative my-2 p-[1px] rounded-xl transition-all duration-300 ${isHovered ? 'bg-gradient-to-r from-[#FF4E00] to-[#874AE3]' : 'bg-gray-200'}`} onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
      <a href={href} onClick={handleClick} className={`not-prose flex ${horizontal ? 'flex-row' : 'flex-col'} font-normal h-full bg-white overflow-hidden w-full cursor-pointer rounded-[11px] no-underline`}>
        {imgUrl && <div className={`relative overflow-hidden flex-shrink-0 ${horizontal ? 'w-[30%] rounded-l-[11px]' : 'w-full'}`} onClick={e => e.stopPropagation()}>
            <img src={imgUrl} alt={title} className="w-full h-full object-cover pointer-events-none select-none" draggable="false" />
            <div className="absolute inset-0 pointer-events-none" />
          </div>}
        <div className={`flex-grow px-6 py-5 ${horizontal ? 'w-[70%]' : 'w-full'} flex flex-col ${horizontal && imgUrl ? 'justify-center' : 'justify-start'}`}>
          {title && <h2 className="font-semibold text-base text-gray-800 m-0">{title}</h2>}
          {description && <div className={`font-normal text-gray-500 re leading-6 ${horizontal || !imgUrl ? 'mt-0' : 'mt-1'}`}>
              <p className="m-0 text-xs">{description}</p>
            </div>}
        </div>
      </a>
    </div>;
};

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/main/mobile/with-swift/example/SmartAccount).
