Skip to content

A platform to connect donors with UCLA students built with smart contracts, Chainlink Functions, and ZKEmail.

Notifications You must be signed in to change notification settings

DhruvPareek/TheBookFund

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

The Book Fund

A proof of concept of a method to disperse funds to targeted recipients using zero knowledge proofs (generated with the ZKEmail library) and an oracle (Chainlink Functions). More specifically, it enables on-chain identity verification via a cryptographic proof from an email and then disperses the relevant amount of USDC based on a mapping of identities to amounts stored in a database accessed by the oracle.

This project creates a platform that connects “donors” to UCLA students who purchase items from a retailer, allowing them to redeem an equivalent amount of USDC. For example, students who buy books at a retailer can receive USDC equal to their book purchases.

Overview

  1. Donor deposits USDC in a smart contract.
  2. Student (Joe Bruin) makes a purchase with a known email address.
  3. Retailer records that purchase amount in their database.
  4. Student proves to a smart contract that they control that email via a zero-knowledge proof.
  5. Student claims the USDC equivalent of their purchase from the smart contract, with the help of a Chainlink Functions oracle that checks the database.

The steps in further detail:

  1. Donor Deposits USDC
    • A donor calls depositUSDC() on TheFund.sol to deposit USDC.
  2. Student Purchase
  3. Proof Generation
    • Joe Bruin generates a cryptographic proof with a zkey generated from the circuits/src/DhruvEmailVerifier.circom circuit.
    • Joe generates the proof using values from an email he received at "[email protected]" as the inputs to the circuit.
    • The proof allows Joe Bruin to prove to others that he is a UCLA student in control of the email address [email protected].
  4. On-Chain Verification
    • Joe Bruin submits this proof to the VerifyEmail() function of contracts/src/TheFund.sol using his ethereum address 0xabc.
    • When the smart contract verifies the proof, "[email protected]" is stored in a mapping in the smart contract as: "[email protected]"-->0xabc.
  5. Redeem USDC
    • Joe Bruin calls the claimFunds() function from contracts/src/TheFund.sol to redeem some amount of USDC corresponding to his purchase of books from the book store.
    • claimFunds() calls requestPriceData() from the EmailOracle smart contract.
    • requestPriceData() uses Chainlink Functions service to make a request to the API "https://y3ugr0hill.execute-api.us-east-1.amazonaws.com/production/[email protected]" (a mockAPI I created to mimick a book store's database).
    • This API request and corresponding oracle request will return $23.94, because that is the value in the database that is saved corresponding to "[email protected]".
    • Upon the oracle request returning, the function fulfill() from the EmailOracle contract will call transferUSDC() from the TheFund contract.
    • transferUSDC() will send $23.94 to Joe Bruin's ethereum address.

Two assumptions:

  • The oracle has access to the book retailer’s purchase database via an API.
  • Donors are willing to donate USDC into the smart contract.

Constraints:

The Circom circuits require the verifying email to be sent by [email protected] and to include an address matching [a-zA-Z0-9._]+@g\.ucla\.edu in the body. Thus, Joe Bruin must receive an email from [email protected] stating "[email protected]" in the message body to produce a valid proof. Examples of valid EML files can be found in circuits/helpers/emls.

File/Code Breakdown

Circuits

The circuits/src folder contains the circom circuits used to generate proofs that verify someone is a UCLA student. Essentially, someone will submit an eml file (which is simply an email that they downloaded) to generate a proof based on these circuits. To understand how ZKEmail's library of circuits works to create cryptographic proofs of the contents and metadata of emails, read more here: https://docs.zk.email/architecture/dkim-verification.

  • circuits/src/DhruvEmailVerifier.circom
    Main circuit that checks DKIM signatures and extracts email metadata.
  • circuits/src/Dhruv_Sender_Regex.circom
    Regex-based sub-circuit (generated by zkregex.com) to verify the sender is [email protected].
  • circuits/src/UCLA_Email_Regex.circom
    Regex-based sub-circuit (generated by zkregex.com) to verify the presence of a UCLA email in the body. Email address needs to match the regex [a-zA-Z0-9._]+@g\.ucla\.edu.
  • circuits/helpers/inputs.ts
    Generates the input JSON for the circuits from an EML file. You can find example EML files in circuits/helpers/emls that can successfully produce a valid proof.

Contracts

The contracts/src folder contains the Solidity smart contracts that implement the on-chain logic for verifying proofs and managing USDC flows (deposits, claims, and disbursements).

  • TheFund.sol

    • Main entry point for users who want to verify their email proofs and claim funds.
    • Key Functions:
      • VerifyEmail():
        • Accepts the zero-knowledge proof parameters.
        • Calls the verifier.sol’s verifyProof() function to validate the proof.
        • If valid, maps the user’s email address to their Ethereum address.
      • claimFunds(emailAddress):
        • Initiates the process of retrieving the user’s purchase amount from the book retailer database (via EmailOracle.sol).
        • Once the oracle returns the purchase amount, triggers the USDC disbursement to the user’s Ethereum address.
      • depositUSDC(amount):
        • Allows donors to deposit or “donate” USDC into the contract so that funds are available for students to claim.
  • EmailOracle.sol

    • Interacts with the Chainlink Functions service to fetch purchase amounts from the external “book purchases” database.
    • Key Functions:
      • requestPriceData(emailAddress):
        • Requests the total cost of purchases corresponding to emailAddress saved in the bookstore database.
      • fullfil(_requestId, _price): - Is the callback function for the oracle service, where _price is the returned price amount. - This function then calls transferUSDC(emailAddr, _amount) with the amount spent by emailAddr.
  • verifier.sol

    • Purpose: Provides the low-level proof verification logic automatically generated by Circom and snarkjs.
    • Key Functions:
      • verifyProof(): Validates the zero-knowledge proof data passed from TheFund.sol. If the proof is valid, TheFund.sol proceeds to map the email to the user’s address.

How to Use

Part 1: Generate The Proof

Follow these steps in the circuits/src folder, these steps are analagous to the Usage Guide for ZKEmail: https://docs.zk.email/zk-email-verifier/usage-guide

  1. Run yarn install
  2. Follow the ZKEmail setup guide to download necessary packages: https://docs.zk.email/zk-email-verifier/setup
  3. Install Rust and Circom: https://docs.circom.io/getting-started/installation/#installing-dependencies
  4. Compile the DhruvEmailVerifier.circom circuit circom -l ../node_modules DhruvEmailVerifier.circom -o --r1cs --wasm --sym --c --O0
  5. Enter circuits/helpers and run npx ts-node inputs.ts to generate the inputs for the circuit. You can see at the bottom of inputs.ts that it is preset to use the LakEmail.eml file to generate inputs.
  6. Compute the witness with the command node DhruvEmailVerifier_js/generate_witness.js DhruvEmailVerifier_js/DhruvEmailVerifier.wasm ../helpers/inputLak.json witness.wtns
  7. Run Phase 2 of the Powers of Tau Ceremony. Follow the initial setup steps and then start from step 11 here: https://github.com/iden3/snarkjs
    • To avoid out-of-memory errors in snarkjs for large circuits, increase Node.js memory with node --max-old-space-size=, where is in kilobytes. node --max-old-space-size=614400 ./../node_modules/.bin/snarkjs
    • To download the powersoftau file: wget https://storage.googleapis.com/zkevm/ptau/powersOfTau28_hez_final_22.ptau
    • This is computationally intensive, so a lot of these steps I've needed run on an AWS EC2 isntance.
  8. Once you have your proof, run snarkjs zkey export soliditycalldata public.json proof.json to get the inputs for the verify() function from the smart contract.

Part 2: Verify Proof + Redeem USDC

  1. Deposit USDC into TheFund.sol.
  2. Call VerifyEmail() in TheFund.sol with the paramters being the result of step 8 from part 1.
  3. Then call claimFunds() with the email address parameter being the receiver of the email used to generate the proof in part 1. For the example given from earlier in the ReadMe file, the parameter would be "[email protected]".
  4. Wait about 15-30 seconds for the oracle to complete its process and USDC to be sent to your wallet.

Other Possibilities

ZKEmail creates a very powerful ability to link Web2 and Web3 identity, allowing people to prove some sort of web2 identity (in this case email address) on-chain. I built on that to programmatically send/receive money based on a web2 identity.

For example, this project could be altered to fund teachers looking to purchase school supplies from Staples (or any other retailer of that type) to stock their classrooms. First, a teacher would purchase school supplies from Staples, then Staples would save her purchase amount alongside her school district email address in their database (ex. "[email protected]"-->$88.61). Then, the teacher would generate a proof using her school supplied email address to prove she is a teacher at Miller Creek Middle School. Finally, a smart contract with API access via an oracle to a Staples database could verify the amount of the teachers' purchase to distribute back to them.

As another example, the UCLA Internet Research Initiative could use a project like this. The UCLA Internet Research Initiative gives 10-15 students $7500 over the course of a school year to spend towards a research project. Every student who wins the 'research scholarship' receives a congradulatory email from Professor Leonard Kleinrock. A project with a framework similar to this one could be created where students who win the research scholarship use their congradulatory email to generate a cryptographic proof, then submit the proof to a smart contract which verifies the validity of the email and disperses $7500 to every person who submits a valid proof. This example would not require an Oracle.

To Do:

  • Create a frontend for proof generation.
  • Create some form of limit on withdraws. You don't want a student to buy $1000 worth of books, then claim $1000 from the smart contract, and then resell all of the books online to make a proft. The amount that can be withdrawan should be limited below $100.
  • Prevent someone from claiming money twice from the same purchase (very simple lol just forgot to do this earlier).
  • Get access to some online retailer's database of purchases.
  • Create some type of work around for the Chainlink Functions because Functions is in Beta.

About

A platform to connect donors with UCLA students built with smart contracts, Chainlink Functions, and ZKEmail.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published