Skip to content

Commit 583c7ca

Browse files
committed
remove duplicate demo link
1 parent 419d311 commit 583c7ca

1 file changed

Lines changed: 41 additions & 40 deletions

File tree

docs/apps/guides/verify-onchain.mdx

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
---
22
title: "Verify Users Onchain"
3-
description: "Enforce Sybil resistance and policy gating inside any Base contract. Base signs a short-lived verification your contract checks in the same transaction as a claim, deposit, or vote, so one real identity counts once and only wallets that meet your bar can participate."
3+
description: "Enforce Sybil resistance and policy gating inside any Base contract. Base Verify signs a short-lived verification your contract checks in the same transaction as a claim, deposit, or vote, so one real identity counts once and only wallets that meet your bar can participate."
44
---
55

6-
## TL;DR
6+
## Summary
77

8-
**Base Verify Onchain lets your smart contract enforce "one real person, once" and gate on real-world traits, like an active Coinbase One membership. The check runs in your contract, so you don't run a verification backend.** Base signs a short-lived verification your contract checks in the same transaction as a claim, deposit, or vote.
8+
**Base Verify Onchain lets your smart contract enforce "one real person, once" and gate on real-world traits, like an active Coinbase One membership. The check runs in your contract, so you don't run a verification backend.** Base Verify signs a short-lived verification your contract checks in the same transaction as a claim, deposit, or vote.
99

10-
<Note>
11-
Live on Base Sepolia! Try the [demo](https://base-verify-onchain-demo.vercel.app/). Please [reach out](https://forms.gle/WTcuWyKkvUV6gGik6) if you have use cases in mind!
12-
</Note>
10+
<Tip>
11+
Live on Base Sepolia! Try the
12+
[demo](https://base-verify-onchain-demo.vercel.app/). Please [reach
13+
out](https://forms.gle/WTcuWyKkvUV6gGik6) if you have use cases in mind!
14+
</Tip>
1315

1416
Integration is three steps:
1517

1618
1. **Deploy or upgrade a contract** to extend `BaseVerifyConsumer` and declare an immutable `provider` and `conditions` (your eligibility policy).
1719
2. **Fetch a verification** in your app: the user signs a SIWE message naming your contract, which you POST to `POST /v1/onchain_verifications`.
1820
3. **Submit** the returned `{ identityHash, expiration, signature }` to your contract, which calls `registry.verifyVerification(...)` and dedupes on `identityHash`.
1921

20-
| What | Value (Base Sepolia) |
21-
| :--- | :--- |
22+
| What | Value (Base Sepolia) |
23+
| :--------------- | :------------------------------------------------------------------------------------------------------------------------------ |
2224
| `SignerRegistry` | [`0x4f15593fbF7e3491d15080e1610E7AF8deBA1a02`](https://sepolia.basescan.org/address/0x4f15593fbF7e3491d15080e1610E7AF8deBA1a02) |
23-
| API base URL | `https://verify.base.dev/v1` |
24-
| Chain | Base Sepolia (`84532`) |
25-
| Consumer base | `BaseVerifyConsumer.sol` |
26-
| Live demo | [base-verify-onchain-demo.vercel.app](https://base-verify-onchain-demo.vercel.app/) |
25+
| API base URL | `https://verify.base.dev/v1` |
26+
| Chain | Base Sepolia (`84532`) |
27+
| Consumer base | `BaseVerifyConsumer.sol` |
2728

2829
Two example consumers to copy from:
2930

@@ -37,24 +38,15 @@ Two example consumers to copy from:
3738
**Base Verify Onchain enforces both directly in your contract.** The Base Verify backend signs a short-lived [EIP-712](https://eips.ethereum.org/EIPS/eip-712) verification that your contract checks in the same transaction as a claim, deposit, mint, or vote. No backend at claim time, and your contract never learns who the user is:
3839

3940
- **Sybil resistance** comes from the `identityHash`. The same real-world identity always produces the same hash for your contract, regardless of which wallet it uses, so your contract counts each real person once.
40-
- **Policy gating** comes from your contract's policy. You declare a `provider` and `conditions` (for example, X followers ≥ 10,000 or an active Coinbase One membership); Base checks the user's real credential against them and only signs when they pass.
41-
42-
**Example use cases:**
43-
44-
- **Sybil-resistant incentives** — one enrollment per real person stops a farmer from multiplying liquidity-mining or points rewards across wallets
45-
- **Gated or permissioned pools** — restrict deposits, borrows, or swaps to verified, policy-gated participants
46-
- **Fair launches and sales** — a per-identity allocation cap keeps bots from sweeping a sale with fresh wallets
47-
- **One-per-person claims, mints, or allowlists** in any app, not just DeFi
48-
- **Gated content, membership, or access** unlocked once per identity
49-
- **One-person-one-vote governance** enforced by the contract
41+
- **Policy gating** comes from your contract's policy. You declare a `provider` and `conditions` (for example, X followers ≥ 10,000 or an active Coinbase One membership); Base Verify checks the user's real credential against them and only signs when they pass.
5042

51-
A single check can do both at once: gate on your policy *and* dedupe on identity in the same transaction. If your app already enforces this offchain (your own backend and database), start with [Verify Social Accounts](/base-account/guides/verify-social-accounts) instead. This guide is for enforcing it in a contract.
43+
A single check can do both at once: gate on your policy _and_ dedupe on identity in the same transaction. If your app already enforces this offchain (your own backend and database), start with [Verify Social Accounts](/base-account/guides/verify-social-accounts) instead. This guide is for enforcing it in a contract.
5244

5345
## Core concepts
5446

5547
### Verification
5648

57-
A short-lived object signed by Base that your contract checks through the `SignerRegistry`. It is signed as EIP-712 typed data and contains:
49+
A short-lived object signed by the Base Verify backend that your contract checks through the `SignerRegistry`. It is signed as EIP-712 typed data and contains:
5850

5951
- `identityHash` — a one-way hash of the user's real-world identity (your dedupe key).
6052
- `policyHash` — binds the verification to your contract's policy on a specific chain. The registry recomputes it onchain, so it never travels in the response.
@@ -70,11 +62,11 @@ The dedupe key. It is deterministic per identity and per contract: the same real
7062

7163
### Policy (provider + conditions)
7264

73-
Your contract declares who is eligible: one `provider` plus one or more `conditions` (for example, an active Coinbase One membership, or X followers greater than or equal to 1000). Base reads this policy directly from your contract and checks the user's stored credential against it before signing.
65+
Your contract declares who is eligible: one `provider` plus one or more `conditions` (for example, an active Coinbase One membership, or X followers greater than or equal to 1000). The Base Verify backend reads this policy directly from your contract and checks the user's stored credential against it before signing.
7466

75-
### Eligibility is enforced by Base
67+
### How eligibility is enforced
7668

77-
Conditions are read from your contract onchain, never taken from the user. Base evaluates them against the user's real stored credential and only signs when they pass, so a user cannot strip or fake a condition to get a verification they are not entitled to.
69+
"Base Verify" here means the Base Verify backend, the off-chain service that holds the signer key, not Base Chain. It reads your contract's `provider` and `conditions` onchain (via `eth_call`), evaluates them against the user's stored credential, and signs a verification only when they pass. Conditions come from your contract, never from the user, so a user cannot strip or fake one to obtain a verification they are not entitled to.
7870

7971
## Architecture and flow
8072

@@ -138,6 +130,7 @@ A claim moves through your app, the Base Verify API, and your contract:
138130
<Warning>
139131
`provider()` and `conditions()` must be immutable (return constants). They are folded into `policyHash`; if they change, every outstanding verification stops verifying and one identity can re-enroll under a new hash, breaking your Sybil resistance.
140132
</Warning>
133+
141134
</Step>
142135

143136
<Step title="Fetch a verification in your app">
@@ -186,6 +179,7 @@ A claim moves through your app, the Base Verify API, and your contract:
186179
<Note>
187180
No API key: the request needs no `Authorization` header because the SIWE signature is the credential.
188181
</Note>
182+
189183
</Step>
190184

191185
<Step title="Submit the verification to your contract">
@@ -205,22 +199,23 @@ A claim moves through your app, the Base Verify API, and your contract:
205199
```
206200

207201
Your contract calls `registry.verifyVerification(...)`; if the signature, expiry, and policy all check out, `enroll()` records the `identityHash`. A second wallet for the same person produces the same `identityHash` and is rejected.
202+
208203
</Step>
209204
</Steps>
210205

211206
### Error handling
212207

213208
If the API does not return `200`, do not submit the transaction. Handle the response by status:
214209

215-
| Response | What to do |
216-
| :-------------------------------- | :---------------------------------------------------------------------------------------------------- |
217-
| **404** `contract_not_found` | The named contract isn't deployed on this chain or doesn't expose a policy. Check the address and chain. |
218-
| **404** `verification_not_found` | The wallet has no credential for your contract's provider. Redirect the user to Base Verify to verify. |
219-
| **404** `needs_reauth` | The credential is older than your contract's cutoff block. Send the user to Base Verify to re-authenticate. |
220-
| **400** `conditions_not_satisfied`| The wallet is verified but does not meet your conditions. Show a message; do not redirect or retry. |
221-
| **400** `invalid_policy` | Your contract's provider/condition/operator combination is unsupported. Fix the contract's policy. |
222-
| **400** `invalid_argument` | Malformed or expired SIWE, wrong statement, or wrong chain. Rebuild the message. |
223-
| **200** | Submit `identityHash`, `expiration`, and `signature` to your contract. |
210+
| Response | What to do |
211+
| :--------------------------------- | :---------------------------------------------------------------------------------------------------------- |
212+
| **404** `contract_not_found` | The named contract isn't deployed on this chain or doesn't expose a policy. Check the address and chain. |
213+
| **404** `verification_not_found` | The wallet has no credential for your contract's provider. Redirect the user to Base Verify to verify. |
214+
| **404** `needs_reauth` | The credential is older than your contract's cutoff block. Send the user to Base Verify to re-authenticate. |
215+
| **400** `conditions_not_satisfied` | The wallet is verified but does not meet your conditions. Show a message; do not redirect or retry. |
216+
| **400** `invalid_policy` | Your contract's provider/condition/operator combination is unsupported. Fix the contract's policy. |
217+
| **400** `invalid_argument` | Malformed or expired SIWE, wrong statement, or wrong chain. Rebuild the message. |
218+
| **200** | Submit `identityHash`, `expiration`, and `signature` to your contract. |
224219

225220
To send a user to Base Verify to complete OAuth, redirect to `https://verify.base.dev` with your app URL and the provider:
226221

@@ -248,7 +243,9 @@ Exchanges a SIWE signature for a signed, short-lived onchain verification. No AP
248243
</ParamField>
249244

250245
<ParamField body="signature" type="string" required>
251-
The wallet's signature over the SIWE message. Base Account smart-wallet ([ERC-1271](https://eips.ethereum.org/EIPS/eip-1271) / [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492)) signatures are supported.
246+
The wallet's signature over the SIWE message. Base Account smart-wallet
247+
([ERC-1271](https://eips.ethereum.org/EIPS/eip-1271) /
248+
[ERC-6492](https://eips.ethereum.org/EIPS/eip-6492)) signatures are supported.
252249
</ParamField>
253250

254251
#### Example request
@@ -273,11 +270,13 @@ curl -X POST https://verify.base.dev/v1/onchain_verifications \
273270
```
274271

275272
<ResponseField name="identityHash" type="string (bytes32)">
276-
One-way hash of the user's real-world identity. Deterministic per identity and per contract. Store it and dedupe on it.
273+
One-way hash of the user's real-world identity. Deterministic per identity and
274+
per contract. Store it and dedupe on it.
277275
</ResponseField>
278276

279277
<ResponseField name="expiration" type="integer">
280-
Unix seconds after which the verification is invalid. Verifications are short-lived (a few minutes), so submit the transaction promptly.
278+
Unix seconds after which the verification is invalid. Verifications are
279+
short-lived (a few minutes), so submit the transaction promptly.
281280
</ResponseField>
282281

283282
<ResponseField name="signature" type="string">
@@ -335,7 +334,9 @@ abstract contract BaseVerifyConsumer {
335334
```
336335

337336
<Note>
338-
`cutoffBlock()` is not part of `policyHash`, so you can change it without invalidating outstanding verifications. Use it to require a fresh authentication (for example, after a policy or security change).
337+
`cutoffBlock()` is not part of `policyHash`, so you can change it without
338+
invalidating outstanding verifications. Use it to require a fresh
339+
authentication (for example, after a policy or security change).
339340
</Note>
340341

341342
### Supported providers and conditions

0 commit comments

Comments
 (0)