This example demonstrates how to use vlayer Web Proof to notarize an HTTP request to:
https://api.etherscan.io/v2/api?chainid=1&module=account&action=tokenbalance&contractaddress=${ERC20_CONTRACT_ADDRESS}&address=${WALLET_ADDRESS}&tag=latest&apikey=${ETHERSCAN_API_KEY}
It generates a zero-knowledge proof (ZK proof) based on the API response, which can then be verified by an on-chain EVM smart contract.
Using this guide, you will learn how to deploy vlayer Prover and Verifier contracts to SepoliaOptimism testnet that prove a user's USDC balance using vlayer web proofs + Etherscan API data.
-
Clone example repository
-
Install foundry and bun to run example - see vlayer install guide here
-
To view the
EtherscanProver.solandEtherscanVerifier.solcontracts, navigate to ./src/vlayerIn
EtherscanProver.solwe define the API to verify. In this case, an Etherscan API that verifies a user's USDC balance:string public constant URL_PREFIX = "https://api.etherscan.io/v2/api?chainid=1&module=account&action=tokenbalance&contractaddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&address=";
If you'd verify a different ERC20 balance, simply update
contractAddressto your ERC20 contract address. -
Install dependencies:
soldeer install -
Compile the contracts:
forge build
-
Install Typescript dependencies
cd vlayer bun install -
Configure testnet environment
In the vlayer directory, create
.env.testnet.localtouch .env.testnet.local
Provide a private key for deploying example contracts and sending transactions to the verifier:
EXAMPLES_TEST_PRIVATE_KEY=0x....Provide a vlayer API token:
VLAYER_API_TOKEN=You can generate your Etherscan API token using the vlayer dashboard
Configure like so:
VLAYER_ENV=testnet bun run deploy.tsNavigate to prove.ts
Add your ETHERSCAN_API_KEY to .env (.env is created with prover and verifier contracts after successful contract deployment :D)
Update the WALLET_ADDRESS (line 14) to the wallet address you want to verify ERC20 balance for.
Then, execute the prover:
VLAYER_ENV=testnet bun run prove.tsUpon successful proof generation:
✅ Proof generated successfully!
💰 Token Balance: 10966806
⏳ Verifying proof on-chain...
📝 Transaction submitted: 0x7c1f4a017945886e14a7fb99b8316715099859dd1fb10700b5342b909dfc2705
⏳ Waiting for transaction confirmation...
✅ Balance verified and stored on-chain!
🎉 PROOF COMPLETE! Summary:
════════════════════════════════
📄 Token Contract: 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
👤 Wallet Address: 0x4B808ec5A5d53871e0b7bf53bC2A4Ee89dd1ddB1
💰 Verified Balance: 10966806
🔗 Verifier Contract: 0x88487279d1b9276c113679744cc63531830748cb
📝 Transaction Hash: 0x7c1f4a017945886e14a7fb99b8316715099859dd1fb10700b5342b909dfc2705
-
vlayer Notary Service: Your request goes to https://test-notary.vlayer.xyz:443 The notary makes the actual HTTP request to Etherscan
-
Notary → Etherscan:
GET https://api.etherscan.io/v2/api?chainid=1&module=account&action=tokenbalance&contractaddress=${ERC20_CONTRACT_ADDRESS}&address=${WALLET_ADDRESS}&tag=latest&apikey=${ETHERSCAN_API_KEY} -
Etherscan Responds:
{ "status": "1", "message": "OK", "result": "10966806" } -
Notary Creates Cryptographic Proof:
- TLS Certificate verification (proves it really connected to etherscan.io)
- HTTP request/response recording (proves what was sent/received)
- Digital signatures (proves data wasn't tampered with)
- Timestamp (proves when it happened)
-
Returns Web Proof: The notary sends back JSON with the cryptographic proof.
