# Sign EIP-7702 authorization

[EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) lets an externally owned account (EOA) delegate its execution to smart-contract code, so an embedded wallet gains account-abstraction features — transaction batching, gas sponsorship, and session keys — while keeping its original address.

:::warning
This applies to **Delegated Accounts** only. EOA and Smart Account types do not require an EIP-7702 authorization.
:::

The authorization is **signed once per chain** — the first transaction that includes it deploys the delegation. Later transactions on the same chain don't need it again; switching to a new chain requires a new authorization.

:::info\[Supported chains vs. other chains]
On a [supported EVM chain](/docs/configuration/chains), Openfort delegates automatically to the **Calibur** implementation (the default unless you configure another) — nothing else to do. On a chain Openfort does not natively support, you can still delegate to any 7702 implementation deployed on that chain by signing the authorization yourself with viem — see [Delegate to a different implementation](#delegate-to-a-different-implementation).
:::

## Recommended: native delegation to Calibur

:::note
Requires `@openfort/react-native` ≥ 1.1.5 (openfort-js ≥ 1.5.0). Earlier versions return an `AA24 signature error` on the first delegated send.
:::

Create the embedded wallet as a Delegated Account, then send a transaction. On the first send, the SDK signs and attaches the one-time EIP-7702 authorization to Openfort's [Calibur](/docs/configuration/addresses) implementation for you — no viem, no manual signing.

Configure a [gas sponsorship](/docs/configuration/gas-sponsorship) on the provider so the send is sponsored. Password recovery needs no backend — just your Shield publishable key:

```tsx [app/_layout.tsx]
<OpenfortProvider
  publishableKey="YOUR_PROJECT_PUBLISHABLE_KEY"
  walletConfig={{
    shieldPublishableKey: 'YOUR_SHIELD_PUBLISHABLE_KEY',
    feeSponsorshipId: { 84532: 'pol_...' }, // Base Sepolia gas sponsorship
  }}
>
  <Slot />
</OpenfortProvider>
```

```tsx [Delegate7702.tsx]
import { Button } from 'react-native'
import { AccountTypeEnum, useEmbeddedEthereumWallet } from '@openfort/react-native'

function Delegate7702() {
  const ethereum = useEmbeddedEthereumWallet()

  // 1. Create a Delegated Account on the target chain (password recovery — no backend).
  const createDelegated = () =>
    ethereum.create({
      recoveryMethod: 'password',
      recoveryPassword: 'user-password',
      accountType: AccountTypeEnum.DELEGATED_ACCOUNT,
      chainId: 84532,
    })

  // 2. The first sponsored send attaches the Calibur authorization automatically.
  const authorize = async () => {
    if (ethereum.status !== 'connected') return
    const txHash = await ethereum.provider.request({
      method: 'wallet_sendCalls',
      params: [
        {
          version: '1.0',
          chainId: '0x14a34', // Base Sepolia (84532)
          from: ethereum.activeWallet.address,
          calls: [{ to: '0x0000000000000000000000000000000000000000', value: '0x0', data: '0x' }],
        },
      ],
    })
    console.log('Delegated:', txHash)
  }

  return (
    <>
      <Button title="Create delegated wallet" onPress={createDelegated} />
      <Button title="Authorize 7702" onPress={authorize} disabled={ethereum.status !== 'connected'} />
    </>
  )
}
```

Using Calibur keeps your transactions visible in the [dashboard](https://dashboard.openfort.io) and lets Openfort act as bundler and paymaster.

## Delegate to a different implementation

Use this path when you want an implementation other than Calibur — the [`Simple` 7702 account](/docs/configuration/addresses) or your own contract — **or when you're on a chain Openfort doesn't natively delegate on** but that has a 7702 implementation available. Sign the authorization yourself with the embedded signer from [`useOpenfortClient`](/docs/products/embedded-wallet/react-native/hooks/useOpenfortClient) and send the UserOperation with [viem](https://viem.sh/). Set `IMPLEMENTATION_ADDRESS` to the target implementation.

:::warning
Only [Openfort-supported implementations](/docs/configuration/addresses) appear in the dashboard and can be tracked. Transactions from a smart account Openfort does not natively support will not show up there.
:::

The embedded signer produces raw ECDSA signatures over a digest, so sign both the authorization and the UserOperation hash with `hashMessage: false` (no EIP-191 prefix).

```tsx [DelegateCustom.tsx]
import { Button } from 'react-native'
import {
  createPublicClient,
  createWalletClient,
  http,
  parseSignature,
  zeroAddress,
  type Address,
  type Hex,
} from 'viem'
import { toAccount } from 'viem/accounts'
import { hashAuthorization } from 'viem/utils'
import {
  createBundlerClient,
  createPaymasterClient,
  toSimple7702SmartAccount,
} from 'viem/account-abstraction'
import { baseSepolia } from 'viem/chains'
import { useEmbeddedEthereumWallet, useOpenfortClient } from '@openfort/react-native'

const CHAIN = baseSepolia
const OPENFORT_RPC_URL = `https://api.openfort.io/rpc/${CHAIN.id}`
const PUBLISHABLE_KEY = process.env.EXPO_PUBLIC_OPENFORT_PUBLISHABLE_KEY!
const FEE_SPONSORSHIP_ID = process.env.EXPO_PUBLIC_OPENFORT_FEE_SPONSORSHIP_ID! // pol_...

// The implementation to delegate to. `Simple` 7702 account (EntryPoint v0.8) shown here.
const IMPLEMENTATION_ADDRESS = '0xe6Cae83BdE06E4c305530e199D7217f42808555B'

function DelegateCustom() {
  const ethereum = useEmbeddedEthereumWallet()
  const client = useOpenfortClient()

  const handleDelegate = async () => {
    if (ethereum.status !== 'connected') return
    const address = ethereum.activeWallet.address as Address

    const signDigest = (hash: Hex) =>
      client.embeddedWallet.signMessage(hash, {
        arrayifyMessage: true,
        hashMessage: false,
      }) as Promise<Hex>

    const owner = Object.assign(
      toAccount({
        address,
        signMessage: ({ message }) =>
          client.embeddedWallet.signMessage(
            typeof message === 'string' ? message : (message.raw as Hex),
          ) as Promise<Hex>,
        signTypedData: () => {
          throw new Error('Not required for the EIP-7702 flow.')
        },
        signTransaction: () => {
          throw new Error('Transactions are sent as UserOperations through the bundler.')
        },
      }),
      {
        sign: ({ hash }: { hash: Hex }) => signDigest(hash),
        signAuthorization: (authorization) => signDigest(hashAuthorization(authorization)),
      },
    )

    const publicClient = createPublicClient({ chain: CHAIN, transport: http() })
    const openfortTransport = http(OPENFORT_RPC_URL, {
      fetchOptions: { headers: { Authorization: `Bearer ${PUBLISHABLE_KEY}` } },
    })

    const account = await toSimple7702SmartAccount({ client: publicClient, owner })
    if (await account.isDeployed()) return

    const bundlerClient = createBundlerClient({
      account,
      client: publicClient,
      paymaster: createPaymasterClient({ transport: openfortTransport }),
      paymasterContext: { feeSponsorshipId: FEE_SPONSORSHIP_ID },
      transport: openfortTransport,
    })

    const walletClient = createWalletClient({ chain: CHAIN, transport: http(), account: owner })
    const preAuthorization = await walletClient.prepareAuthorization({
      contractAddress: IMPLEMENTATION_ADDRESS,
    })
    const authorization = {
      ...preAuthorization,
      ...parseSignature(await signDigest(hashAuthorization(preAuthorization))),
    }

    const userOpHash = await bundlerClient.sendUserOperation({
      calls: [{ to: zeroAddress, value: 0n, data: '0x' }],
      authorization,
    })
    const receipt = await bundlerClient.waitForUserOperationReceipt({ hash: userOpHash })
    console.log('Delegated:', receipt.receipt.transactionHash)
  }

  return (
    <Button
      title="Delegate to a custom implementation"
      onPress={handleDelegate}
      disabled={ethereum.status !== 'connected'}
    />
  )
}
```

## Related

* [Account types](/docs/products/embedded-wallet/account-types)
* [Entity addresses](/docs/configuration/addresses) — supported implementations per chain
* [Send Ethereum transaction](/docs/products/embedded-wallet/react-native/wallet/actions/send-transaction/ethereum)
* [Sign EIP-7702 authorization (React)](/docs/products/embedded-wallet/react/wallet/actions/eip-7702-authorization)
