Nothing on this page asks you to trust the site. Each row is a value you can read off the chain, a command you can run, or a test you can execute. Bring a terminal and a healthy dose of suspicion.
Everything on Creditcoin CC3 testnet, chainId 102031. The table below is the reproducible deployment, the one you can run end to end with World's simulator. The Orb-tree deployment for real verified humans follows it.
| Contract | Address | Source |
|---|---|---|
| AttestedWorldID (Ethereum mainnet) | 0x1122…68ad | deployments.json |
| AttestedWorldID (Sepolia staging) | 0x3a7c…cef7 | deployments.json |
| HumanRegistry | 0x62c2…298d | deployments.json |
| CreditLine | 0xbb97…56d9 | deployments.json |
| hUSD | 0x4bd7…9640 | deployments.json |
| HumanGate | 0xa3e0…776c | deployments.json |
| HumanPoll | 0xd785…13bc | deployments.json |
| RelayReward | 0x9766…afe0 | deployments.json |
| HumanLinks | 0xbbf6…781c | deployments.json |
| CreditHistory | 0xa483…3404 | deployments.json |
| EthRepay | 0x231c…fc48 | deployments.json |
| BlockProver precompile | 0x0000…0FD2 | native |
| ChainInfo precompile | 0x0000…0fD3 | native |
| AttestorStash precompile | 0x0000…0fd4 | native |
| EvmV1Decoder library | 0x04B9…D18B | shared |
| World ID manager · Ethereum | 0xf713…ddEa | chainKey 3 |
| World ID manager · Sepolia | 0xb2Ea…7076 | chainKey 1 |
The same contracts verifying against the Ethereum mainnet identity tree instead of Sepolia staging, with 30 days terms, for people with an Orb-verified World ID. Open /app?profile=production to use it. hUSD and both AttestedWorldID instances are shared with the table above.
| Contract | Address |
|---|---|
| HumanRegistry | 0x53fc…96af |
| CreditLine | 0x30ca…77d7 |
| HumanGate | 0x5442…5b93 |
Receipts, not instructions. A real World ID identity verified on Creditcoin, and a full borrow-and-repay cycle, both with transaction hashes you can open.
The same verification AttestedWorldID performs, as a read-only call.
Copy, paste, run. `cast` is Foundry: curl -L https://foundry.paradigm.xyz | bash && foundryup.
Every attack in the security model, the guard that stops it, and the test that fires it.
| Attack | Reverts with | Test |
|---|---|---|
| Forged root | BatchProofRejected() | AttestedWorldID.t.sol :: test_SingleExecuteRevertsWhenTheProverRejectsTheProof |
| Tampered payload | BatchProofRejected() | AttestedWorldID.t.sol :: test_BatchRevertsWhenTheProverRejectsTheProof |
| Wrong source chain | WrongSourceChain(uint64,uint64) | AttestedWorldID.t.sol :: test_RevertsOnWrongSourceChain |
| Reverted source transaction |
The twelve attacks, fired at the deployed contracts as read-only calls while this page loaded. No wallet, no gas. The chain says no, and it says it by name.
Firing twelve attacks at CC3 testnet…
Gas, the batch cap, latency, proof size and precompile share, measured on the live chains by one command.
Collected 2026-09-13T09:17:14.146Z by bun run worker/src/cli.ts measure; every table is in docs/MEASUREMENTS.md.
What the widget is pinned to, and what the registry pinned itself to at deployment.
The worker's own log, committed to the repo at evidence/relay-log.jsonl.
141 entries in evidence/relay-log.jsonl, showing the newest 50.
hashToField(abi.encodePacked(wallet)), the same value the widget below recomputes from the deployed contract.IDKit.request({... allow_legacy_proofs: true, environment: "staging"}).preset(orbLegacy({ signal: wallet })), rp_context signed with the Humanline RP key (rp_84b02642423cadf5).--recurse-submodules, then bun install && (cd contracts && bun install). Foundry is not vendored. Install it with curl -L https://foundry.paradigm.xyz | bash && foundryup.Every contract test, including the negative paths
cd contracts && forge test -vv
Only the negative paths
52 tests. Each one should reject the attack listed below, most with a named custom error.
cd contracts && forge test --match-test "Revert|Rejects|Ignores|Cannot|Survives|Expire|Specific" -vvv
One row from the table below
Every test name in that table is checked against contracts/test/*.t.sol by web's own test suite, so none of them can be invented.
cd contracts && forge test --match-test "^test_RevertsOnThinAttestorQuorum$" -vvv
Fork tests against live CC3 state
Skipped unless CC3_FORK is set, so the default suite stays hermetic.
cd contracts && CC3_FORK=https://rpc.cc3-testnet.creditcoin.network forge test --match-contract Fork -vv
Web unit tests: World ID hashing and formatting
Reproduces hashToField and the external nullifier exactly as the Solidity does.
cd web && bun test
Build a proof for any Ethereum transaction
The same endpoint the widget above uses.
cast rpc --rpc-url https://rpc.cc3-testnet.creditcoin.network eth_blockNumber # proof builder (chainKey 3 = Ethereum mainnet) https://prover.cc3-testnet.creditcoin.network/api/v1/proof-by-tx/3/<txHash>
| SourceTxReverted() |
| AttestedWorldID.t.sol :: test_RevertsWhenTheSourceTxReverted |
| Transaction sent to another contract | NotIdentityManager(address) | AttestedWorldID.t.sol :: test_RevertsWhenTheCalleeIsNotTheIdentityManager |
| Decoy TreeChanged from another emitter | proof invalid | AttestedWorldID.t.sol :: test_IgnoresDecoyTreeChangedFromAnotherEmitter |
| Contract creation instead of a call | NotIdentityManager(address) | AttestedWorldID.t.sol :: test_RevertsWhenTheTransactionIsAContractCreation |
| No TreeChanged log at all | NoTreeChange() | AttestedWorldID.t.sol :: test_RevertsWhenThereIsNoTreeChange |
| Two genuine TreeChanged logs | AmbiguousTreeChange(uint256) | AttestedWorldID.t.sol :: test_RevertsOnTwoGenuineTreeChangedLogs |
| An unknown function selector | UnsupportedEntrypoint(bytes4) | AttestedWorldID.t.sol :: test_RevertsOnAnUnknownSelector |
| Truncated calldata | UnsupportedEntrypoint(bytes4) | AttestedWorldID.t.sol :: test_RevertsOnTruncatedCalldata |
| Calldata that disagrees with the log | CalldataLogMismatch() | AttestedWorldID.t.sol :: test_RevertsWhenCalldataRootsDisagreeWithTheLog |
| Out-of-order root | UnknownPreRoot(uint256) | AttestedWorldID.t.sol :: test_RevertsOnAnUnknownPreRootAfterBootstrap |
| Root from an unfinalised block | NotFinal(uint64,uint64) | AttestedWorldID.t.sol :: test_RevertsWhenTheSourceBlockIsNotFinalYet |
| Thin attestor set | ThinQuorum(uint32,uint32) | AttestedWorldID.t.sol :: test_RevertsOnThinAttestorQuorum |
| Replayed query | QueryAlreadyProcessed(bytes32) | AttestedWorldID.t.sol :: test_RevertsOnReplayOfTheSameQuery |
| A query replayed inside a batch | QueryAlreadyProcessed(bytes32) | AttestedWorldID.t.sol :: test_BatchRejectsARepeatedQueryInsideOneBatch |
| A batch replaying a root already relayed singly | QueryAlreadyProcessed(bytes32) | AttestedWorldID.t.sol :: test_BatchRejectsAQueryAlreadyRelayedSingly |
| Overwriting a recorded root | CannotOverwriteRoot() | AttestedWorldID.t.sol :: test_RevertsWhenARootWouldBeOverwritten |
| Oversized batch | BatchTooLarge(uint256) | AttestedWorldID.t.sol :: test_BatchRejectsMoreThanTen |
| Out-of-order batch | BatchOutOfOrder() | AttestedWorldID.t.sol :: test_BatchRejectsOutOfOrderHeights |
| Empty batch | EmptyBatch() | AttestedWorldID.t.sol :: test_BatchRejectsEmpty |
| Mismatched batch arrays | BatchLengthMismatch() | AttestedWorldID.t.sol :: test_BatchRejectsMismatchedLengths |
| Stale root past expiry | ExpiredRoot() | AttestedWorldID.t.sol :: test_RootsExpireAfterOneWeek |
| An ancient root side-filled for a fresh expiry | ExpiredRoot() | AttestedWorldID.t.sol :: test_AnAncientSideFilledRootArrivesAlreadyExpired |
| A proof against a root that was never relayed | NonExistentRoot() | AttestedWorldID.t.sol :: test_VerifyProofRejectsAnUnknownRootBeforeTouchingTheVerifier |
| A garbage zero-knowledge proof | proof invalid | AttestedWorldID.t.sol :: test_VerifyProofRejectsAGarbageProof |
| Proof for a different wallet, or reused across actions | proof invalid | HumanRegistry.t.sol :: test_RevertsWhenTheProofIsRejected |
| A signal that is not the caller | proof invalid | HumanRegistry.t.sol :: test_TheSignalHashIsCallerSpecific |
| Double registration | WalletAlreadyHuman(address,uint256) | HumanRegistry.t.sol :: test_RevertsWhenTheWalletAlreadyBelongsToAnotherHuman |
| Re-binding to the wallet already bound | SameWallet() | HumanRegistry.t.sol :: test_RevertsOnRegisteringTheSameWalletTwice |
| Registering a zero nullifier | ZeroNullifier() | HumanRegistry.t.sol :: test_RevertsOnAZeroNullifier |
| Acting from a non-human wallet | NotHuman(address) | CreditLine.t.sol :: test_NonHumansCannotTouchTheLine |
| Borrowing without a line | NoLine(uint256) | CreditLine.t.sol :: test_BorrowingWithoutALineReverts |
| Borrowing over the limit | OverLimit(uint256,uint256) | CreditLine.t.sol :: test_BorrowingPastTheLimitReverts |
| Borrowing more than the pool holds | InsufficientLiquidity(uint256,uint256) | CreditLine.t.sol :: test_BorrowingMoreThanTheIdleBalanceReverts |
| A second line for the same human | LineExists(uint256) | CreditLine.t.sol :: test_ASecondWalletCannotOpenASecondLine |
| Opening twice from one wallet | LineExists(uint256) | CreditLine.t.sol :: test_OpeningTwiceFromTheSameWalletReverts |
| Default freeze survives a re-bind | LineFrozen(uint256) | CreditLine.t.sol :: test_DefaultSurvivesAWalletRebind |
| Declaring a default too early | NotInDefault(uint256,uint64,uint64) | CreditLine.t.sol :: test_MarkDefaultBeforeGraceEndsReverts |
| Declaring a default on a clean line | NothingOwed(uint256) | CreditLine.t.sol :: test_MarkDefaultOnACleanLineReverts |
| Withdrawing more shares than you own | InsufficientShares(uint256,uint256) | CreditLine.t.sol :: test_WithdrawingMoreSharesThanHeldReverts |
| A first-depositor donation attack | proof invalid | CreditLine.t.sol :: test_ADonationAttackCannotSkimTheNextDepositor |
| Zero-value calls | ZeroAmount() | CreditLine.t.sol :: test_ZeroAmountsRevert |
{"production_status":"registered","staging_status":"registered"}Fired live just now against Creditcoin CC3 testnet: 12 of 12 refused with the expected named revert. Sepolia attested tip 12011900, 7 bonded attestors.
| Attack | Refused with |
|---|---|
| Forged Merkle proof | Error: Merkle proof validation failed |
| Wrong contract called | NotIdentityManager(0x1c7D4B19…) |
| Reverted source transaction | SourceTxReverted |
| Replay an adopted root | QueryAlreadyProcessed(0x46cecbe3…) |
| Roots out of order | BatchOutOfOrder |
| Unattested block height | Error: Continuity proof does not match attestation or checkpoint |
| Below the attestor floor | ThinQuorum(7, 1000) |
| Wrong source chain | WrongSourceChain(1, 3) |
| Decoy TreeChanged log | Error: Merkle proof validation failed |
| Oversize batch (11) | BatchTooLarge(11) |
| Root from before the history | UnknownPreRoot(1374574688…) |
| One human, a second registration | SameWallet |