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

# Gated content with EOA discovery

> Use sdk.context.startale.eoaWallets to recognize a user's legacy assets and unlock content inside your Mini App.

If your project already has a user base (players with progress, collectors with NFTs, customers with purchase history), those users have everything tied to their personal wallets. Inside a Mini App, the connected wallet is a brand-new smart account. This walkthrough uses `sdk.context.startale.eoaWallets` to bridge the gap.

## What you'll build

Inside your Mini App:

1. Read the user's verified linked EOAs from the host context.
2. Check whether any of them holds a specific NFT.
3. Unlock content (or prompt the user to take an action) based on that check.

## Prerequisites

* A working Mini App from [Build your first Mini App](/tutorials/code-walkthroughs/build-first-miniapp).
* An NFT contract address on Soneium that you want to gate against.

<Note>
  The Mini App sandbox does not simulate `eoaWallets`. Test this flow against staging or the production Startale App.
</Note>

## Steps

### 1. Read linked EOAs

```tsx theme={null}
import { useEffect, useState } from 'react'
import { sdk } from '@farcaster/miniapp-sdk'

const [eoas, setEoas] = useState<string[]>([])

useEffect(() => {
  void sdk.context.then((ctx) => {
    setEoas(ctx.startale?.eoaWallets ?? [])
  })
}, [])
```

### 2. Check NFT ownership across all linked EOAs

```ts theme={null}
import { createPublicClient, erc721Abi, http } from 'viem'
import { soneium } from 'viem/chains'

const NFT_CONTRACT = '0xLegacyNftContract...' as const

const publicClient = createPublicClient({
  chain: soneium,
  transport: http(),
})

async function holdsLegacyNft(addresses: string[]) {
  for (const address of addresses) {
    const balance = await publicClient.readContract({
      address: NFT_CONTRACT,
      abi: erc721Abi,
      functionName: 'balanceOf',
      args: [address as `0x${string}`],
    })
    if (balance > 0n) return true
  }
  return false
}
```

### 3. Render gated content

```tsx theme={null}
const [hasNft, setHasNft] = useState<boolean | null>(null)

useEffect(() => {
  if (eoas.length === 0) {
    setHasNft(false)
    return
  }
  void holdsLegacyNft(eoas).then(setHasNft)
}, [eoas])

if (hasNft === null) return <Spinner />

return hasNft
  ? <PremiumContent />
  : <PromptToLinkEoa />
```

### 4. Handle the "no linked EOA" case

If `eoaWallets` is empty, the user has not linked an EOA to their Startale account. Prompt them to do so, but the actual linking happens **outside** the Mini App, in the Startale App's settings.

```tsx theme={null}
function PromptToLinkEoa() {
  return (
    <div>
      <p>Want to access your existing collection? Link your wallet in the Startale App settings.</p>
      <a href="https://app.startale.com/settings/wallets">Open settings</a>
    </div>
  )
}
```

## Important constraints

* You can only **read** from a linked EOA inside a Mini App. You cannot sign or send transactions from it. See [Wallet integration](/miniapps/wallet-integration).
* Each address in `eoaWallets` is verified server-side via SIWE. Treat them as cryptographically owned: they are safe to use for eligibility checks, identity matching, and analytics.

## What you've learned

* That `eoaWallets` is the canonical bridge between a user's legacy identity and their new Startale smart account.
* How to do read-only contract calls against linked EOAs inside a Mini App.
* That EOA linking itself happens outside the Mini App, your job is to detect and react.
