advancedcookbook
ZK credit score gate
Prove credit ≥ 700 without revealing the score.
Combine Long HTTP (`0x0805`) to fetch a third-party credit API + ZK Proofs (`0x0806`) to prove a threshold without revealing the underlying value. The TEE attests both the API response and the ZK circuit — gate any contract feature on "score above N" with zero leakage.
Architecture
Phase 1 Phase 2 (callback)
┌──────┐ fetch ┌────────────┐ prove ┌──────────┐ proof ┌──────────┐
│ User │ ────────▶ │ LongHTTP │ ───────▶ │ ZK 0x806 │ ──────▶ │ Gate │
│ tx │ │ 0x0805 │ in TEE │ │ │ verifies │
└──────┘ └────────────┘ └──────────┘ └────┬─────┘
│
▼
user authorized
(score ≥ 700, but
actual score never
touched chain)Code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {PrecompileConsumer} from "./utils/PrecompileConsumer.sol";
contract ZKCreditGate is PrecompileConsumer {
address constant ZK = address(0x806);
address constant ASYNC_DELIVERY = 0x5A16214fF555848411544b005f7Ac063742f39F6;
bytes32 public constant CREDIT_CIRCUIT =
0x0000000000000000000000000000000000000000000000000000000000000000; // your circuit hash
mapping(address => bool) public verified;
/// @notice User triggers proof generation. Backed by their hashed identity.
function requestProof(bytes calldata circuitInput, address executor)
external returns (bytes32 jobId)
{
// ExecutorRequest layout (NOT LongRunningRequest — silent revert otherwise)
bytes memory input = abi.encode(
executor, circuitInput, block.number + 200,
CREDIT_CIRCUIT, address(this), this.onZKResultDelivered.selector,
300_000, 1_000_000_000, 100_000_000, uint256(0),
new bytes[](0), new bytes[](0), bytes(""), bytes("")
);
(bool ok, bytes memory result) = ZK.call(input);
require(ok, "zk submit failed");
jobId = abi.decode(result, (bytes32));
}
function onZKResultDelivered(bytes32, bytes calldata result) external {
require(msg.sender == ASYNC_DELIVERY, "unauth");
// Result is the ZK proof. The chain verifies it as part of settlement —
// delivery success ⇒ proof valid ⇒ user passed the threshold.
// (extract user address from circuit public inputs in real impl)
verified[tx.origin] = true;
}
modifier onlyVerified() {
require(verified[msg.sender], "credit gate failed");
_;
}
}