# Sign EIP-7702 authorization

[EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) allows an externally owned accounts (EOA) to delegate their execution to smart contract code
This allows EOA wallets to gain account abstraction capabilities such as transaction bundling, gas sponsorship, and custom permissions.

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

Openfort provides methods to sign EIP-7702 authorizations, which allows your embedded wallets to be upgraded into any smart contract.
Despite you can sign an authorization for any smart account, when using openfort to send transactions from `delegated accounts`, only a limited list of smart account implementations is supported.
[Learn more](/docs/configuration/addresses) about the supported list of smart accounts.

When sending a transaction from a Delegated Account through Openfort, you must sign a one-time EIP-7702 authorization.
This authorization tells the network which smart account implementation contract the EOA is delegating to.

* The authorization is **signed once per chain** — after the first transaction is submitted with the authorization, subsequent transactions on the same chain do not need it again.
* When switching to a **new chain**, a new authorization must be signed for that chain.

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

The simplest path is to configure the embedded wallet as a Delegated Account and let the SDK attach the authorization for you. Set `accountType` to `DELEGATED_ACCOUNT` in [`walletConfig.ethereum`](/docs/products/embedded-wallet/react/wallet/ethereum#setting-the-account-type):

```tsx [Providers.tsx]
<OpenfortProvider
  publishableKey="YOUR_OPENFORT_PUBLISHABLE_KEY"
  walletConfig={{
    shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY",
    ethereum: {
      chainId: 84532,
      accountType: AccountTypeEnum.DELEGATED_ACCOUNT,
      ethereumFeeSponsorshipId: { 84532: 'pol_...' },
    },
  }}
>
  {children}
</OpenfortProvider>
```

Then send a transaction as usual — for example with wagmi's `useSendTransaction`, or the [send guide](/docs/products/embedded-wallet/react/wallet/actions/send-transaction/ethereum). On the first send, the SDK signs and attaches the one-time EIP-7702 authorization to Openfort's [Calibur](/docs/configuration/addresses) implementation, keeping your transactions visible in the [dashboard](https://dashboard.openfort.io).

## 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 `use7702Authorization` hook and send the UserOperation with viem.

:::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.
:::

### Sign the authorization

Use the `use7702Authorization` hook from the Openfort React SDK:

```tsx [Authorize7702.tsx]
import { use7702Authorization } from '@openfort/react'
import { usePublicClient, useAccount } from 'wagmi'
import { sepolia } from 'viem/chains'

function Authorize7702() {
  const { signAuthorization } = use7702Authorization()
  const publicClient = usePublicClient()
  const { address } = useAccount()

  const handleAuthorization = async () => {
    if (!address) throw new Error('Wallet not connected')

    const nonce = await publicClient.getTransactionCount({ address })

    const signedAuth = await signAuthorization({
      contractAddress: '0xe6Cae83BdE06E4c305530e199D7217f42808555B',
      chainId: sepolia.id,
      nonce,
    })

    console.log('Authorization signed:', signedAuth)
    // Pass signedAuth to your transaction flow
  }

  return <button onClick={handleAuthorization}>Sign Authorization</button>
}
```

### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `contractAddress` | `Address` | The implementation contract to delegate execution to |
| `chainId` | `number` | The chain ID for the authorization |
| `nonce` | `number` | The current transaction count of the EOA |

### Return value

The `signAuthorization` function returns a `SignedAuthorization` object:

```ts
type SignedAuthorization = {
  address: Address
  chainId: number
  nonce: number
  r: Hex
  s: Hex
  v: bigint
  yParity: number
}
```

### Use the authorization in a transaction

Once signed, pass the authorization to your transaction. Here is an example using Openfort as a bundler and paymaster for gasless execution:

```tsx [useUserOperation.ts]
import { useCallback } from 'react'
import { http, zeroAddress } from 'viem'
import { baseSepolia } from 'viem/chains'
import {
  createPaymasterClient,
  createBundlerClient,
  entryPoint08Address,
} from 'viem/account-abstraction'
import { toSimpleSmartAccount } from 'viem/account-abstraction'
import { useWalletClient, usePublicClient } from 'wagmi'

const OPENFORT_RPC_URL = `https://api.openfort.io/rpc/${baseSepolia.id}`
const OPENFORT_PUBLISHABLE_KEY = process.env.NEXT_PUBLIC_OPENFORT_PUBLISHABLE_KEY!
const OPENFORT_FEE_SPONSORSHIP_ID = process.env.NEXT_PUBLIC_OPENFORT_FEE_SPONSORSHIP_ID!

export function useUserOperation() {
  const { data: walletClient } = useWalletClient()
  const publicClient = usePublicClient()

  return useCallback(async (authorization: SignedAuthorization) => {
    if (!walletClient) throw new Error('Wallet client not ready')

    const simpleSmartAccount = await toSimpleSmartAccount({
      owner: walletClient,
      entryPoint: { address: entryPoint08Address, version: '0.8' },
      client: publicClient,
      address: walletClient.account.address,
    })

    const paymasterClient = createPaymasterClient({
      transport: http(OPENFORT_RPC_URL, {
        fetchOptions: {
          headers: {
            'Authorization': `Bearer ${OPENFORT_PUBLISHABLE_KEY}`,
          },
        },
      }),
    })

    const bundlerClient = createBundlerClient({
      account: simpleSmartAccount,
      client: publicClient,
      paymaster: paymasterClient,
      paymasterContext: {
        policyId: OPENFORT_FEE_SPONSORSHIP_ID,
      },
      transport: http(OPENFORT_RPC_URL, {
        fetchOptions: {
          headers: {
            'Authorization': `Bearer ${OPENFORT_PUBLISHABLE_KEY}`,
          },
        },
      }),
    })

    const txnHash = await bundlerClient.sendUserOperation({
      calls: [{ to: zeroAddress, data: '0x', value: 0n }],
      authorization,
    })

    const receipt = await bundlerClient.waitForUserOperationReceipt({
      hash: txnHash,
    })

    return receipt.receipt.transactionHash
  }, [walletClient, publicClient])
}
```

## Delegate an external wallet (server-side)

The flow above upgrades an Openfort embedded wallet from the browser. You can also delegate a **third-party or external wallet** — for example one held in Privy or Turnkey — to an Openfort Delegated Account from your server with the [`@openfort/openfort-node`](/docs/products/server) SDK. The wallet signs a single EIP-7702 authorization; Openfort then sponsors and submits the transaction.

:::warning
Wallets like MetaMask or Rabby do not support signing external EIP-7702 authorizations. Use a wallet whose SDK exposes authorization signing.
:::

Before you start, create an Openfort project, a [gas sponsorship](/docs/configuration/gas-sponsorship) (note the `pol_...` ID), and a [contract](/docs/configuration/addresses) (note the `con_...` ID).

```ts [delegate-external-wallet.ts]
import 'dotenv/config'
import Openfort, { createAccountV2 } from '@openfort/openfort-node'
import { generatePrivateKey, privateKeyToAccount, signAuthorization } from 'viem/accounts'
import { createWalletClient, http, serializeSignature } from 'viem'
import { baseSepolia } from 'viem/chains'

const openfort = new Openfort(process.env.OPENFORT_SECRET_KEY!)
const chainId = baseSepolia.id

// 1. Your third-party wallet (replace key generation with your wallet SDK)
const privateKey = generatePrivateKey()
const account = privateKeyToAccount(privateKey)

// 2. Register it as a Delegated Account
const openfortAccount = await createAccountV2({
  chainType: 'EVM',
  address: account.address,
  accountType: 'Delegated Account',
  chainId,
  implementationType: 'Calibur',
})

// 3. Sign the EIP-7702 authorization with the external wallet
const walletClient = createWalletClient({ chain: baseSepolia, transport: http(), account })
const authorization = await walletClient.prepareAuthorization({
  account: account.address,
  contractAddress: openfortAccount.smartAccount.implementationAddress,
})
const serializedAuthorization = serializeSignature(
  await signAuthorization({ ...authorization, privateKey }),
)

// 4. Create a sponsored transaction intent that uses the authorization
const txIntent = await openfort.transactionIntents.create({
  chainId,
  account: openfortAccount.id,
  policy: 'pol_...', // your gas sponsorship ID
  signedAuthorization: serializedAuthorization,
  interactions: [
    { contract: 'con_...', functionName: 'mint', functionArgs: [account.address] },
  ],
})

// 5. Sign the intent's payload with the external wallet and submit
const signature = await account.sign({ hash: txIntent.nextAction.payload.signableHash })
const result = await openfort.transactionIntents.signature(txIntent.id, { signature })
console.log('Transaction hash:', result.transactionHash)
```

:::info
This example generates a private key with [Viem](https://viem.sh/) for demonstration. Replace it with your third-party wallet's signing SDK.
:::

## Related

* [`use7702Authorization` hook reference](/docs/products/embedded-wallet/react/hooks/use7702Authorization)
* [Account types](/docs/products/embedded-wallet/account-types)
* [Send Ethereum transaction](/docs/products/embedded-wallet/react/wallet/actions/send-transaction/ethereum)
* [Switch chain](/docs/products/embedded-wallet/react/wallet/actions/switch-chain)
