diff --git a/docs/learn/poh-tutorial.mdx b/docs/learn/poh-tutorial.mdx new file mode 100644 index 0000000000..4ade39be60 --- /dev/null +++ b/docs/learn/poh-tutorial.mdx @@ -0,0 +1,355 @@ +--- +title: Proof of Humanity tutorial +description: Learn how to verify users with Proof of Humanity V2 on Linea. +image: /img/socialCards/verify-users-with-proof-of-humanity.jpg +--- + +Proof of Humanity (PoH) lets you verify whether a wallet belongs to a real human on Linea. It +provides a simple and reliable way for projects to gate access to rewards or features exclusively for +verified users. + +PoH V2 is powered by a single attestation issued by Sumsub through the Verax Attestation Registry. +This version replaces the (too) complex multi-provider setup that was used for PoH V1, simplifying +verification to a single, trusted data source. + +## The Sybil problem + +In Web3, identity is fluid, meaning users can create as many wallets as they want. This openness +fuels innovation but also creates opportunities for abuse. A Sybil attack occurs when one actor +generates multiple fake identities to exploit a system designed for fair participation. + +Common examples include: + +- Airdrop farming, where a single individual controls thousands of wallets to claim rewards. +- Fake voting in DAOs or community governance, undermining collective decisions. +- Spam campaigns that flood onchain communities or social apps. +- Automated account creation to game loyalty programs or incentive systems. + +Recent data shows how widespread this problem has become. Nansen and other web3 analytics firms +have revealed that a significant share of wallet activity in certain programs comes from non-human +or clustered entities. For instance, several major projects recently had to filter tens of millions +of wallets to preserve fairness in their distributions (e.g. Linea had to filter more than half a +million wallets to preserve our TGE from farmers). + +The takeaway is clear: without human verification, decentralized systems remain vulnerable. Linea's +Proof of Humanity V2 addresses this by providing developers a reliable way to ensure "one human, +one action." + +## Why verifying users matters + +Verifying users isn't about restricting access - it's about building integrity into digital +communities and economies. + +For developers, it means: + +- Preventing fraud and abuse by excluding automated or duplicate accounts. Bots inflate all your + metrics, giving you misleading data about your app growth and you end up optimizing for noise, not + real adoption. +- Protecting incentive systems like governance tokens, loyalty points, or rewards programs. Bots can + quickly drain incentives systems without adding value, PoH helps you target your spending to real + users only. +- Reducing moderation costs by ensuring real humans drive community engagement. + +For users, it builds: + +- Trust and fairness, knowing that everyone participates on equal footing. +- Safety, by reducing exposure to spam, scams, or bots. +- Reputation portability, since a verified identity can be reused across multiple dapps within the + Linea ecosystem. + +Verification also enables new categories of applications — from proof-of-personhood voting to +verified social reputation, identity-based access control, or even credit scoring. + +## Unlocking growth through verification + +Human verification isn't just a security measure — it's a growth accelerator. + +When users trust that interactions are genuine, engagement and retention improve. Developers can +focus on building features instead of moderating spam or chasing fraudulent claims. Communities +become healthier, and token incentives circulate among real participants. + +With PoH V2, Linea dapps can: + +- Simplify onboarding with a single verification flow across the ecosystem. +- Enhance brand credibility by signaling transparency and integrity. +- Foster sustainable ecosystems, where every wallet represents a verified human being. This will + fuel every human-to-human interaction, knowing bots won't have a seat at the table. + +Trust, in this context, becomes a competitive advantage, and a key differentiator for web3 +applications aiming to scale responsibly. + +## Verify: how users complete their Proof of Humanity + +You can integrate Proof of Humanity in your app to restrict access, rewards or actions to real users +only. Use the **Sumsub Proof of Personhood flow** to allow users to verify their humanity directly +from your app. This flow handles user verification through **Sumsub's Proof of Personhood** flow and +issues a **Verax attestation** onchain. + +:::tip Before you start +You'll need: + +- A frontend app connected to the Linea network +- A reliable Linea Mainnet RPC provider such as [Infura](https://developer.metamask.io) +- A way to read the user's wallet address (e.g. [Wagmi](https://wagmi.sh/react/api/hooks/useAccount)) +::: + +### Typical flow + +Here's how the complete user verification process works step-by-step: + +1. The user connects their Ethereum wallet. +2. Your app queries the Linea PoH API to check whether the user is already verified. Endpoint: + `https://poh-api.linea.build/poh/v2/{address}` Documentation + [here](https://poh-api.linea.build/#/PoH/PohController_getOnePOHv2). + +The endpoint returns `true` if the address is verified, or `false` otherwise. Use `false` to trigger +the Sumsub flow (next step). + +3. Your app asks them to sign a message, containing 2 variables: + + - Their wallet address + - A timestamp (ISO date) + +The signature is used by Sumsub to confirm wallet ownership and link the verification to the correct +address onchain. A recommended way to sign the message is to use Wagmi's +[`useSignMessage` hook](https://wagmi.sh/react/api/hooks/useSignMessage): + +```tsx +import {useAccount, useSignMessage} from "wagmi"; + +function App() { + const { address } = useAccount(); + const { signMessage } = useSignMessage(); + + const date = new Date().toISOString(); + + return ( + + ); +} +``` + +Note: this message contains the Linea Mainnet chain ID (59144). + +4. Generate a link including this signed payload and redirect to it, or open it in an iframe. You + need to encode the JSON payload in base64 to safely include it in the Sumsub verification URL. + +Payload to encode: + +```json +{ + "signInMessage": "in.sumsub.com wants you to sign in with your Ethereum account:\n\n\nI confirm that I am the owner of this wallet and consent to performing a risk assessment and issuing a Verax attestation to this address.\n\nURI: https://in.sumsub.com\nVersion: 1\nChain ID: 59144\nIssued At: ", + "signature": "" +} +``` + +You then need to generate a base64-encoded JSON from this payload, to be used as the `msg` +parameter to append to the URL below: + +```typescript +const msg = btoa(JSON.stringify(payload)); +const url = new URL("https://in.sumsub.com/websdk/p/uni_BKWTkQpZ2EqnGoY7"); +url.search = new URLSearchParams({ msg }).toString(); +``` + +5. The Sumsub verification process happens on their side. +6. Once verified, the user is redirected back to your app, or your frontend receives a message event + from the iframe wrapper. Listening for the event: + +```typescript +const iframe = document.getElementById("sumsub-frame") as HTMLIFrameElement; +const ac = new AbortController(); + +window.addEventListener( + "message", + (e: MessageEvent) => { + if (e.source !== iframe.contentWindow) return; + if (e.origin !== "https://in.sumsub.com") return; + + if (e.data.status === "completed") { /* proceed */ } + + ac.abort(); + }, + { signal: ac.signal }, +); +``` + +Alternatively, you can redirect users back to your app via a callback URL instead of using an +iframe. + +7. You can then query the Linea PoH API to confirm that the attestation has been issued onchain. + Endpoint: `https://poh-api.linea.build/poh/v2/{address}` Documentation + [here](https://poh-api.linea.build/#/PoH/PohController_getOnePOHv2). + +### Notes + +- The attestation is issued only if none exists for this wallet address. +- It may take a few seconds before the attestation is visible onchain after verification. +- Once verification is complete, you can programmatically confirm a user's PoH status using either + an API or an onchain contract (see below). + +## Check: how to confirm verification status + +Once users have completed verification, you can confirm their Proof of Humanity status through an +API call or onchain verification. + +The APIs presented below are free to use, without any key or authentication. + +### Offchain verification + +The API base URL for the service is: `https://poh-api.linea.build/` + +**Usage (GET):** + +Call the endpoint with the format: `https://poh-api.linea.build/poh/v2/{address}` + +**Example:** + +```bash +curl https://poh-api.linea.build/poh/v2/0xc5fd29cC1a1b76ba52873fF943FEDFDD36cF46C6 +# Content-Type: text/plain; +# Body: "true" | "false" +``` + +**Response:** + +The response is raw text, not JSON. + +- `false` = address does not have PoH status. +- `true` = address has PoH status. + +**Example:** + +```typescript +const res = await fetch(`.../poh/v2/${address}`); +if (!res.ok) throw new Error(`HTTP ${res.status}`); +const text = (await res.text()).trim(); // "true" | "false" +const isHuman = text === "true"; +``` + +**Reference:** + +You can explore all available endpoints and test them directly from the [Swagger +UI](https://poh-api.linea.build/#/PoH/PohController_getOnePOH). + +### Signed onchain verification V2 + +If you need fully onchain verification (e.g. from a smart contract), you can use the signed PoH +status, and the `PohVerifier` contract. The +[`PohVerifier.sol` contract](https://lineascan.build/address/0xBf14cFAFD7B83f6de881ae6dc10796ddD7220831) +can be used together with a trusted source of PoH status data. + +#### 1. Get signed PoH status + +The API base URL for the service is: `https://poh-signer-api.linea.build/` + +**Usage (GET):** + +Call the endpoint with the format: `https://poh-signer-api.linea.build/poh/v2/{address}` + +**Example:** + +```bash +curl https://poh-signer-api.linea.build/poh/v2/0xc5fd29cC1a1b76ba52873fF943FEDFDD36cF46C6 +# Content-Type: text/plain; charset=utf-8 +# 0xa11a6c92fa0027d9de2a0c8ab363b1af083497da57f871c93aeb9efcd32ffaeb677fafb2c005e8165181713220b8a1da2f70ed31d7820b8fa086a8e7361dbf121c +``` + +This returns a signed message that contains the PoH status of the provided address. Response +format: plain text (not JSON). + +Example response: + +``` +0xa11a6c92fa0027d9de2a0c8ab363b1af083497da57f871c93aeb9efcd32ffaeb677fafb2c005e8165181713220b8a1da2f70ed31d7820b8fa086a8e7361dbf121c +``` + +Example: + +```typescript +const sig = await (await fetch(`https://poh-signer-api.linea.build/poh/v2/${address}`)).text(); +await pohVerifier.verify(sig, address); // See step 2 +``` + +#### 2. Call `PohVerifier.sol` + +Call the `verify()` function with the signed message and the address of the account being queried. +The contract confirms that the signed message was issued by the trusted signer and returns a +boolean. + +```solidity +function verify( + bytes memory signature, + address human +) external view virtual returns (bool){ ... } +``` + +Parameters: + +- `signature`: The signed message from the previous step. +- `address`: The address of the account being queried. + +It returns a boolean: + +- `true`: The account has PoH status. +- `false`: The account does not have PoH status. + +Example: + +```solidity +import { IPohVerifier } from "./interfaces/IPohVerifier.sol"; + +error PohVerificationFailed(address sender); + +/* ... */ + +if (!pohVerifier.verify(signature, msg.sender)) { + revert PohVerificationFailed(msg.sender); +} + +/* ... */ +``` + +## Ensuring security and reliability + +Proof of Humanity V2 is built with robust security, privacy, and transparency in mind. + +- Trusted verification: All attestations are issued by Sumsub, a regulated KYC provider with + industry-standard compliance. +- Onchain transparency: Every verification is recorded through the Verax Attestation Registry, + ensuring public verifiability. +- User privacy: Only the attestation (not personal data) is stored onchain — maintaining a balance + between identity assurance and privacy. +- System reliability: The PoH API handles rate limits, temporary downtimes, and blockchain + propagation gracefully, ensuring developers always receive accurate verification states. + +Developers can confidently integrate PoH knowing it provides a secure, composable, and future-proof +foundation for identity-driven experiences. + +### A note on privacy + +When users complete the verification flow, Sumsub processes a face-video and biometric images to +check for liveness and identity-document match, but they only stores a hash, they do not store the +full image. + +Sumsub adheres to the General Data Protection Regulation (GDPR) principles (lawful, transparent, +purpose-limited, minimal, secure), and implements ISO/IEC 27001/27017/27018, SOC 2 Type 2 and +PCI-DSS security frameworks, giving users the best standards for data protection and privacy. + +For our most privacy savvy users, we're working on a privacy-preserving verification alternative that +will give you further control while still ensuring "one-human-one-wallet" trust. + +## Conclusion + +Proof of Humanity V2 is a true enable of growth for all builders and dapps on the Linea ecosystem. +By giving dapps the ability to verify real humans, easily, securely, and onchain, it helps transform +the way web3 applications grow and interact with their communities. + +If you're building on Linea, PoH V2 is now live and available through our developer documentation. + +Start verifying your users today, and build experiences meant for real humans. +