International Prescription Validation with Dual-Doctor Zero-Knowledge Proofs on Flare
Enabling trustless international healthcare through zero-knowledge proofs and decentralized verification on Flare Network
When patients travel internationally, their medical prescriptions face critical challenges:
- π« Not Recognized: Prescriptions from home countries aren't accepted abroad
β οΈ No Verification: Pharmacies can't verify foreign prescriptions' authenticity- π Privacy Concerns: Traditional verification exposes sensitive medical data
- π Manual Processes: Paper-based systems prone to fraud and errors
- π Regulatory Gaps: No international standard for cross-border prescriptions
Real Impact: Millions of travelers annually face medication access problems, leading to health risks and emergency room visits.
TravelScript creates a decentralized, privacy-preserving prescription validation system using:
Doctor 1 (Home Country) β Creates prescription with ZK proof
β
Doctor 2 (Destination) β Validates prescription with ZK proof
β
Flare FDC β Attests prescription metadata on-chain
β
Pharmacy (Anywhere) β Verifies and dispenses medication safely
Key Benefits:
- β Privacy-First: Doctors prove credentials without revealing identity
- β Trustless: No central authority, verified on Flare blockchain
- β International: Works across borders with local doctor validation
- β Fraud-Proof: ZK proofs + nullifier system prevents double-signing
- β Transparent: All verifications immutably recorded on-chain
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FRONTEND (Next.js 14) β
β β’ Doctor Registration Portal β
β β’ Prescription Creation Interface β
β β’ Validation Dashboard β
β β’ Pharmacy Verification Portal β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INTEGRATION LAYER (TypeScript) β
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββββββββββ β
β β FDC Client β β EVVM β β Semaphore ZK β β
β β β β Processor β β Proof Generator β β
β β β’ Request β β β’ Create Rx β β β’ Identity Gen β β
β β β’ Verify β β β’ Validate β β β’ Proof Gen β β
β β β’ Attest β β β’ Attest β β β’ Nullifier Track β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββββββ¬ββββββββββββ β
β β β β β
βββββββββββΌβββββββββββββββββββΌβββββββββββββββββββββββΌββββββββββββββ
β β β
β β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FLARE COSTON2 BLOCKCHAIN β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PrescriptionHub.sol (0x6fB0ce...CBCC2E3) β β
β β β Dual-doctor verification β β
β β β Semaphore ZK proof validation β β
β β β Nullifier-based fraud prevention β β
β β β FDC attestation storage β β
β β β Pharmacy verification queries β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β EVVM (0x37628b...EC74) β β
β β β Custom chain support β β
β β β Gasless transactions (future) β β
β β β Enhanced transaction processing β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β FDC Hub (0x1c78A0...B55b) β β
β β β Metadata attestations β β
β β β Data availability layer β β
β β β Cryptographic proof verification β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TravelScript uniquely combines three cutting-edge technologies to create a privacy-preserving, trustless prescription system:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LAYER 1: SEMAPHORE (Privacy Layer) β
β β’ Zero-Knowledge Proofs β
β β’ Anonymous Doctor Authentication β
β β’ Nullifier-Based Fraud Prevention β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
β ZK Proofs
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LAYER 2: EVVM (Execution Layer) β
β β’ Smart Contract Deployment (PrescriptionHub) β
β β’ On-Chain Verification Logic β
β β’ Event Emission & State Management β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
β Attestation Hash
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LAYER 3: FDC (Data Availability Layer) β
β β’ Metadata Attestation β
β β’ Cryptographic Proof Generation β
β β’ Decentralized Data Verification β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 1: DOCTOR 1 CREATES PRESCRIPTION β
β Integration: SEMAPHORE β EVVM β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1οΈβ£ SEMAPHORE: Generate Doctor Identity
ββ Doctor connects wallet (0xDoctor1...)
ββ Frontend calls: createDoctorIdentity(walletAddress)
β ββ Creates Semaphore identity
β β’ Commitment: Hash of identity secret
β β’ Private key: Exported for storage
ββ Store locally: { commitment, wallet, country, license }
ββ β
Doctor registered anonymously
2οΈβ£ SEMAPHORE: Generate ZK Proof for Prescription
ββ Doctor fills prescription form (medication, dosage, etc.)
ββ Hash prescription data: keccak256(prescriptionData)
ββ Generate ZK proof:
β Input:
β β’ Identity (private - stays in browser)
β β’ Prescription hash (public)
β β’ Group ID (1 = doctors group)
β Output:
β β’ Proof array: uint256[8]
β β’ Nullifier: bytes32 (unique per prescription + doctor)
β β’ Merkle root: bytes32
ββ β
Proof generated (proves doctor credentials without revealing identity)
3οΈβ£ EVVM: Submit to Blockchain
ββ Frontend calls: EVVMProcessor.createPrescription()
ββ Encodes prescription data:
β ββ ABI.encode([patientName, medication, dosage, frequency, duration, notes])
ββ Submits transaction to PrescriptionHub contract:
β ββ createPrescription(
β prescriptionId: "RX-AR-20241123-001",
β prescriptionData: encoded_data,
β doctor1Proof: [uint256[8]],
β doctor1Nullifier: 0xabc123...,
β patientAddress: 0xPatient...
β )
ββ SMART CONTRACT EXECUTES:
β ββ Verify prescription doesn't exist
β ββ Verify nullifier not used (prevents double-signing)
β ββ Call Semaphore.verifyProof() - ZK VERIFICATION
β β ββ If proof invalid β REVERT
β ββ Store prescription:
β β ββ prescriptions[id] = Prescription({
β β prescriptionHash: keccak256(data),
β β doctor1Nullifier: 0xabc123...,
β β doctor2Nullifier: 0x0,
β β patientAddress: 0xPatient...,
β β timestamp: block.timestamp,
β β validated: false,
β β active: true,
β β fdcAttestationHash: 0x0
β β })
β ββ Mark nullifier as used:
β β ββ usedNullifiers[0xabc123...] = true
β ββ Emit event:
β ββ PrescriptionCreated(prescriptionId, hash, nullifier, patient)
ββ β
Transaction confirmed on Flare Coston2
ββ Gas paid in C2FLR
ββ Block explorer: https://coston2-explorer.flare.network/tx/0x...
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 2: DOCTOR 2 VALIDATES PRESCRIPTION β
β Integration: SEMAPHORE β EVVM β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1οΈβ£ SEMAPHORE: Second Doctor Identity
ββ Different doctor connects (0xDoctor2...)
ββ Registers Semaphore identity (different commitment)
ββ β
Second doctor registered
2οΈβ£ SEMAPHORE: Generate Validation Proof
ββ Doctor 2 enters prescription ID: "RX-AR-20241123-001"
ββ Query blockchain: getPrescriptionFromChain(id)
ββ Reviews prescription data
ββ Generates ZK proof for SAME prescription hash:
β Input:
β β’ Different identity (Doctor 2's secret)
β β’ Same prescription hash (from blockchain)
β β’ Same group ID (1)
β Output:
β β’ Different proof array
β β’ Different nullifier: 0xdef456...
ββ β
Second proof generated (different doctor, same prescription)
3οΈβ£ EVVM: Submit Validation
ββ Frontend calls: EVVMProcessor.validatePrescription()
ββ Submits transaction:
β ββ validatePrescription(
β prescriptionId: "RX-AR-20241123-001",
β doctor2Proof: [uint256[8]],
β doctor2Nullifier: 0xdef456...
β )
ββ SMART CONTRACT EXECUTES:
β ββ Load prescription from storage
β ββ Verify prescription exists
β ββ Verify not already validated
β ββ Verify nullifier not used (different from doctor 1)
β ββ Call Semaphore.verifyProof() with prescription hash
β β ββ Verifies Doctor 2 is authorized AND different from Doctor 1
β ββ Update prescription:
β β ββ prescription.doctor2Nullifier = 0xdef456...
β β ββ prescription.validated = true
β ββ Mark nullifier as used:
β β ββ usedNullifiers[0xdef456...] = true
β ββ Emit event:
β ββ PrescriptionValidated(prescriptionId, nullifier)
ββ β
Prescription now validated by TWO doctors
ββ Both proofs verified
ββ Both nullifiers unique
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 3: FDC ATTESTATION (AUTOMATIC) β
β Integration: EVVM β FDC β EVVM β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1οΈβ£ PREPARE METADATA
ββ Frontend reads prescription from blockchain
ββ Constructs metadata object:
β ββ {
β prescriptionId: "RX-AR-20241123-001",
β prescriptionHash: "0x789abc...",
β issuer: {
β commitment: "0xabc123...",
β walletAddress: "0xDoctor1...",
β country: "Argentina",
β timestamp: 1700000000
β },
β validator: {
β commitment: "0xdef456...",
β walletAddress: "0xDoctor2...",
β country: "USA",
β timestamp: 1700003600
β },
β data: {
β patientName: "MarΓa GarcΓa",
β medication: "Amoxicillin 500mg",
β dosage: "1 tablet",
β frequency: "Every 8 hours",
β duration: "7 days"
β }
β }
ββ β
Metadata prepared
2οΈβ£ FDC: Upload to Public URL
ββ Store metadata in browser localStorage (MVP)
β ββ localStorage.setItem(`prescription-${id}`, JSON.stringify(metadata))
ββ Generate public URL:
β ββ https://api.travelscript.health/prescription/RX-AR-20241123-001
β ββ (In production: IPFS hash or real API endpoint)
ββ β
Metadata publicly accessible
3οΈβ£ FDC: Request Attestation
ββ Frontend calls: FDCClient.requestAttestation(metadataUrl)
ββ Prepare FDC request:
β ββ {
β attestationType: "0x4a736f6e417069..." (bytes32 of "JsonApi"),
β sourceId: "0x74726176656c73..." (bytes32 of "travelscript"),
β requestBody: {
β url: "https://api.travelscript.health/prescription/...",
β jq_transformation: "." (return full JSON)
β }
β }
ββ POST to FDC Verifiers:
β ββ POST https://fdc-verifiers-testnet.flare.network/
β Headers: { "Content-Type": "application/json" }
β Body: FDC request
ββ FDC VERIFIER NETWORK PROCESSES:
β ββ Multiple verifiers fetch the URL
β ββ Verify data matches expected format
β ββ Start voting round
β ββ Response: {
β status: "VALID",
β response: {
β attestationType: "JsonApi",
β sourceId: "travelscript",
β votingRound: "12345",
β lowestUsedTimestamp: "1700003600",
β requestBody: {...},
β responseBody: { metadata }
β }
β }
ββ β
Attestation request accepted
ββ Voting Round: 12345 started
4οΈβ£ FDC: Wait for Finalization
ββ Round duration: 90 seconds
ββ FDC network reaches consensus
ββ Frontend polls or waits:
β ββ await new Promise(resolve => setTimeout(resolve, 90000))
ββ β
Round finalized
5οΈβ£ FDC: Retrieve Proof from DAL
ββ Frontend calls: FDCClient.getProofFromDAL(votingRound, prescriptionId)
ββ GET request:
β ββ GET https://fdc-dal-testnet.flare.network/proof/12345/travelscript/RX-AR-20241123-001
ββ DAL RETURNS MERKLE PROOF:
β ββ {
β merkleProof: [
β "0xhash1...",
β "0xhash2...",
β "0xhash3..."
β ],
β data: {
β attestationType: "JsonApi",
β sourceId: "travelscript",
β votingRound: "12345",
β lowestUsedTimestamp: "1700003600",
β requestBody: {...},
β responseBody: {...}
β }
β }
ββ β
Cryptographic proof obtained
6οΈβ£ FDC: Verify Proof On-Chain
ββ Frontend calls: FDCClient.verifyProofOnChain(proof, provider)
ββ Encode proof for contract:
β ββ ABI.encode(['merkleProof', 'data'], proof)
ββ Call FDC Hub contract:
β ββ FDCHub.verifyAttestation(
β attestationType: bytes32,
β sourceId: bytes32,
β encodedProof: bytes
β )
ββ FDC HUB CONTRACT EXECUTES:
β ββ Verify Merkle proof against stored root
β ββ Verify voting round is finalized
β ββ Verify data integrity
β ββ Return: true (proof valid) or false (invalid)
ββ β
Proof verified on-chain
7οΈβ£ EVVM: Store Attestation Hash
ββ Calculate attestation hash:
β ββ attestationHash = keccak256(JSON.stringify(attestationResponse))
β ββ 0xjkl012...
ββ Frontend calls: EVVMProcessor.attestPrescription()
ββ Submit transaction:
β ββ PrescriptionHub.attestPrescription(
β prescriptionId: "RX-AR-20241123-001",
β fdcAttestationHash: 0xjkl012...
β )
ββ SMART CONTRACT EXECUTES:
β ββ Load prescription from storage
β ββ Verify prescription exists
β ββ Verify prescription is validated (2 doctors)
β ββ Verify not already attested
β ββ Store FDC hash:
β β ββ prescription.fdcAttestationHash = 0xjkl012...
β ββ Emit event:
β ββ PrescriptionAttested(prescriptionId, fdcAttestationHash)
ββ β
FDC attestation permanently stored on blockchain
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 4: PHARMACY VERIFICATION β
β Integration: EVVM Query β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1οΈβ£ EVVM: Query Prescription
ββ Pharmacist enters prescription ID
ββ Frontend calls: EVVMProcessor.canFillPrescription(id)
ββ Query smart contract (read-only, no gas):
β ββ PrescriptionHub.canFillPrescription("RX-AR-20241123-001")
ββ SMART CONTRACT LOGIC:
β ββ function canFillPrescription(string calldata prescriptionId)
β external view returns (bool canFill, string memory reason)
β {
β Prescription memory rx = prescriptions[prescriptionId];
β
β if (rx.timestamp == 0) {
β return (false, "Prescription does not exist");
β }
β
β if (!rx.active) {
β return (false, "Prescription revoked");
β }
β
β if (!rx.validated) {
β return (false, "Not validated by second doctor");
β }
β
β if (rx.fdcAttestationHash == bytes32(0)) {
β return (false, "Not attested by FDC");
β }
β
β return (true, "Valid - both doctors verified via ZK proof");
β }
ββ Response:
β ββ canFill: true
β ββ reason: "Valid - both doctors verified via ZK proof"
ββ β
Prescription verified safe to dispense
2οΈβ£ Display Full Prescription Data
ββ Query: getPrescriptionFromChain(id)
ββ Returns:
β ββ {
β prescriptionHash: "0x789abc...",
β doctor1Nullifier: "0xabc123...", β Proves Doctor 1 signed
β doctor2Nullifier: "0xdef456...", β Proves Doctor 2 validated
β patientAddress: "0xPatient...",
β timestamp: 1700000000,
β validated: true, β Both doctors approved
β active: true, β Not revoked
β fdcAttestationHash: "0xjkl012..." β FDC verified metadata
β }
ββ Decode prescription data from chain/localStorage
ββ β
Pharmacist sees full verified prescription
3οΈβ£ Dispense Medication
ββ Pharmacist confirms all checks pass:
β β
Two doctor signatures (verified via ZK)
β β
FDC attestation (metadata verified)
β β
Active prescription (not revoked)
β β
Valid patient address
ββ β
Medication dispensed safely
- Without Semaphore: Doctors' identities exposed on-chain
- With Semaphore: Only commitments (numbers) stored, true identity hidden
- Benefit: HIPAA/GDPR compliant, doctors maintain anonymity
- Without EVVM: Need multiple blockchains, complex bridging
- With EVVM: Single deployment on Flare with enhanced capabilities
- Benefit: Simplified architecture, lower gas costs, future gasless tx
- Without FDC: Metadata only in frontend (can be lost/manipulated)
- With FDC: Cryptographically proven metadata, decentralized storage
- Benefit: Tamper-proof prescription details, always accessible
SEMAPHORE EVVM FDC
β β β
ZK Proof βββββββββββΊ Smart Contract βββββββΊ Attestation
(Who signed) (What was signed) (Proof of data)
β β β
ββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββ
β
Complete Verification
(Who + What + Proof)
Result:
- β Privacy-preserving (Semaphore)
- β On-chain verification (EVVM)
- β Data integrity (FDC)
- β Trustless (No intermediaries)
- β International (Works anywhere)
Purpose: Deploy custom PrescriptionHub contract with enhanced transaction capabilities
Implementation: lib/evvm/processor.ts
class EVVMProcessor {
// Create prescription on-chain (Doctor 1)
async createPrescription(prescription, semaphoreProof, patientAddress) {
// Encodes prescription data
// Submits to PrescriptionHub contract
// Emits PrescriptionCreated event
}
// Validate prescription (Doctor 2)
async validatePrescription(prescriptionId, semaphoreProof) {
// Verifies second ZK proof
// Marks prescription as validated
// Emits PrescriptionValidated event
}
// Attest with FDC (automatic)
async attestPrescription(prescription) {
// Calls FDC client to request attestation
// Stores attestation hash on-chain
// Emits PrescriptionAttested event
}
}Smart Contract: contracts/PrescriptionHub.sol
contract PrescriptionHub {
struct Prescription {
bytes32 prescriptionHash; // Hash of medication data
bytes32 doctor1Nullifier; // First doctor's ZK nullifier
bytes32 doctor2Nullifier; // Second doctor's ZK nullifier
address patientAddress; // Patient's wallet
uint256 timestamp; // Creation time
bool validated; // Second doctor validated
bool active; // Not revoked
bytes32 fdcAttestationHash; // FDC proof hash
}
// Doctor 1 creates prescription with ZK proof
function createPrescription(
string calldata prescriptionId,
bytes calldata prescriptionData,
uint256[8] calldata doctor1Proof,
bytes32 doctor1Nullifier,
address patientAddress
) external;
// Doctor 2 validates with ZK proof
function validatePrescription(
string calldata prescriptionId,
uint256[8] calldata doctor2Proof,
bytes32 doctor2Nullifier
) external;
// Store FDC attestation hash
function attestPrescription(
string calldata prescriptionId,
bytes32 fdcAttestationHash
) external;
// Pharmacy verifies prescription
function canFillPrescription(string calldata prescriptionId)
external view returns (bool canFill, string memory reason);
}Deployment:
- Network: Flare Coston2 Testnet
- Contract:
0x6fB0ce1685Fcfa6EeDdDFc4607a9ccbd5CBCC2E3 - EVVM Instance:
0x37628b685c84a67cDd350D626a572857DFCcEC74 - Explorer: https://coston2-explorer.flare.network/address/0x6fB0ce1685Fcfa6EeDdDFc4607a9ccbd5CBCC2E3
Purpose: Privacy-preserving doctor authentication using zero-knowledge proofs
Implementation: lib/semaphore.ts
// Create doctor's Semaphore identity
function createDoctorIdentity(walletAddress: string) {
const identity = new Identity();
const commitment = identity.commitment.toString();
const privateKey = identity.export();
return { identity, commitment, privateKey };
}
// Generate ZK proof for prescription signing
function generateSemaphoreProof(
identity: Identity,
groupId: bigint,
message: bigint
) {
// Generates zero-knowledge proof
// Proves: "I'm a registered doctor" without revealing which one
// Produces nullifier to prevent double-signing
return { proof, nullifier, merkleTreeRoot };
}How It Works:
Doctor Registration:
1. Doctor connects wallet
2. Generate Semaphore identity (commitment)
3. Store commitment + wallet address
β No personal info on-chain
β Identity is just a number (commitment)
Prescription Signing:
1. Doctor creates/validates prescription
2. Generate ZK proof:
β’ Input: Identity + prescription hash
β’ Output: Proof + nullifier
3. Submit to smart contract
β Contract verifies proof
β Contract checks nullifier not used
β Prescription signed anonymously
Privacy Guarantees:
- β Anonymity: No one knows which doctor signed (except the doctor)
- β Unlinkability: Can't link multiple prescriptions to same doctor
- β Fraud Prevention: Nullifier prevents same doctor signing twice
- β Verifiability: Anyone can verify the proof is valid
Nullifier System:
mapping(bytes32 => bool) public usedNullifiers;
function createPrescription(..., bytes32 nullifier) {
require(!usedNullifiers[nullifier], "Already signed");
usedNullifiers[nullifier] = true;
// Doctor can't sign same prescription again
}βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β STEP 1: DOCTOR 1 CREATES PRESCRIPTION (Argentina) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 1. Dr. Juan PΓ©rez (Argentina) connects wallet β
β 2. Registers Semaphore identity β
β β’ Commitment: 0xabc123... β
β β’ Country: Argentina β
β 3. Patient: MarΓa GarcΓa needs Amoxicillin β
β 4. Creates prescription: β
β β’ Medication: Amoxicillin 500mg β
β β’ Duration: 7 days β
β 5. Generates ZK proof: β
β β’ Proves: "I'm a registered doctor" β
β β’ Nullifier: 0xdef456... (prevents double-sign) β
β 6. Submit to blockchain: β
β PrescriptionHub.createPrescription() β
β β
Event: PrescriptionCreated β
β 7. Prescription ID: RX-AR-20241123-001 β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β STEP 2: DOCTOR 2 VALIDATES PRESCRIPTION (USA) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 1. Patient travels to USA, needs medication β
β 2. Dr. Sarah Johnson (USA) connects wallet β
β 3. Registers Semaphore identity β
β β’ Commitment: 0x789xyz... β
β β’ Country: USA β
β 4. Enters prescription ID: RX-AR-20241123-001 β
β 5. Reviews prescription details β
β 6. Generates ZK proof: β
β β’ Proves: "I'm a different registered doctor" β
β β’ Nullifier: 0xghi789... (unique, prevents reuse) β
β 7. Submit validation to blockchain: β
β PrescriptionHub.validatePrescription() β
β β
Event: PrescriptionValidated β
β 8. Status: Validated by 2 doctors β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β STEP 3: FDC ATTESTATION (Automatic) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 1. Prescription metadata prepared: β
β { β
β prescriptionId: "RX-AR-20241123-001", β
β issuer: { country: "Argentina", timestamp: ... }, β
β validator: { country: "USA", timestamp: ... }, β
β medication: "Amoxicillin 500mg" β
β } β
β 2. Upload to public URL (IPFS/API) β
β URL: https://api.travelscript.health/rx/RX-AR-... β
β 3. Request FDC attestation: β
β POST https://fdc-verifiers-testnet.flare.network/ β
β β
Voting Round: 12345 started β
β 4. Wait for finalization (~90 seconds) β
β β’ FDC verifiers validate data β
β β’ Consensus reached β
β 5. Retrieve proof from DAL: β
β GET https://fdc-dal-testnet.flare.network/proof/12345/... β
β β
Cryptographic proof obtained β
β 6. Verify proof on FDC Hub: β
β FDCHub.verifyAttestation(proof) β
β β
Proof valid β
β 7. Store attestation hash on PrescriptionHub: β
β PrescriptionHub.attestPrescription(attestationHash) β
β β
Event: PrescriptionAttested β
β 8. Hash: 0xjkl012... β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β STEP 4: PHARMACY VERIFICATION (USA) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 1. Patient arrives at pharmacy with ID: RX-AR-20241123-001 β
β 2. Pharmacist enters prescription ID in portal β
β 3. Query blockchain: β
β PrescriptionHub.canFillPrescription("RX-AR-20241123-001") β
β 4. Smart contract checks: β
β β
Prescription exists β
β β
Doctor 1 signed (ZK proof verified) β
β β
Doctor 2 validated (ZK proof verified) β
β β
FDC attested (metadata verified) β
β β
Not revoked β
β β
Active prescription β
β 5. Response: "Valid - both doctors verified via ZK proof" β
β 6. Pharmacist reviews: β
β β’ Medication: Amoxicillin 500mg β
β β’ Issuer: Argentina doctor β β
β β’ Validator: USA doctor β β
β β’ FDC: Attested β β
β 7. Dispense medication safely β
β 8. β
Patient receives treatment β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- β Travel Freely: Prescriptions work internationally
- β Fast Access: No bureaucracy or delays
- β Privacy: Medical data stays private with ZK proofs
- β Control: Can revoke prescriptions anytime
- β Anonymous Signing: Privacy-preserving with ZK proofs
- β International Recognition: Cross-border validity
- β Fraud Prevention: Nullifier prevents double-signing
- β Audit Trail: All actions recorded on-chain
- β Instant Verification: Real-time blockchain queries
- β Trustless: No central authority needed
- β Compliance: Cryptographic proof of validation
- β Transparency: Complete audit trail
- β Reduced Fraud: ZK proofs + nullifiers prevent tampering
- β Lower Costs: No intermediaries or paperwork
- β Better Data: Analytics without compromising privacy
- β Global Standard: Works across all countries
# 1. Install Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup
# 2. Install Node.js 18+
node --version
# 3. Get C2FLR testnet tokens
# Visit: https://faucet.flare.network/coston2# 1. Clone repository
git clone https://github.com/yourusername/travelscript
cd travelscript
# 2. Deploy smart contract (if needed)
cd evvm-deployment
cp .env.example .env
# Add your PRIVATE_KEY
forge build
make deploy
# Contract deployed at: 0x6fB0ce1685Fcfa6EeDdDFc4607a9ccbd5CBCC2E3
# 3. Configure frontend
cd ../travelscript-app
cp .env.example .env.local
# Add NEXT_PUBLIC_PRESCRIPTION_HUB_ADDRESS
# Add NEXT_PUBLIC_PROJECT_ID (from cloud.reown.com)
# 4. Install and run
npm install
npm run dev
# 5. Open browser
# http://localhost:3000Test Scenario: Argentina β USA
-
Doctor 1 (Argentina):
- Visit
/doctor - Register: Dr. Juan PΓ©rez, Argentina
- Create prescription for patient
- Copy Prescription ID
- Visit
-
Doctor 2 (USA):
- New incognito window (different wallet)
- Visit
/doctor/validate - Register: Dr. Sarah Johnson, USA
- Enter Prescription ID
- Validate prescription
- Wait ~90 seconds for FDC attestation
-
Pharmacy (USA):
- Visit
/pharmacy - Enter Prescription ID
- See: β Valid - both doctors verified
- Dispense medication
- Visit
travelscript/
βββ contracts/ # Smart contracts
β βββ PrescriptionHub.sol # Main prescription contract
β
βββ evvm-deployment/ # Foundry deployment
β βββ src/
β β βββ PrescriptionHub.sol # Contract for deployment
β βββ script/
β β βββ DeployPrescriptionHub.s.sol # Deployment script
β βββ .env.example # Environment template
β βββ Makefile # Deployment commands
β
βββ travelscript-app/ # Next.js frontend
β βββ app/
β β βββ doctor/ # Doctor registration & creation
β β β βββ page.tsx # Registration portal
β β β βββ validate/
β β β βββ page.tsx # Validation interface
β β βββ pharmacy/
β β β βββ page.tsx # Pharmacy verification
β β βββ layout.tsx # Root layout with AppKit
β β
β βββ lib/
β β βββ fdc/
β β β βββ client.ts # FDC client implementation
β β β βββ attestation-service.ts # FDC service layer
β β βββ evvm/
β β β βββ processor.ts # EVVM blockchain processor
β β β βββ prescription-contract.ts # Contract interface
β β βββ config/
β β β βββ constants.ts # App configuration
β β β βββ flare-network.ts # Network config
β β βββ semaphore.ts # ZK proof generation
β β
β βββ types/
β β βββ prescription.ts # TypeScript types
β β
β βββ context/
β β βββ index.tsx # AppKit configuration
β β
β βββ .env.example # Environment template
β
βββ README.md # This file
βββ DEPLOYMENT_GUIDE.md # Complete deployment guide
βββ DEPLOYMENT_SUCCESS.md # Deployment status
βββ QUICKSTART.md # 5-minute quick start
βββ DEPLOYMENT_CHECKLIST.txt # Deployment checklist
- What: Cryptographic proofs that verify statements without revealing data
- How: Doctors prove credentials without exposing identity
- Why: Privacy-preserving authentication
- Benefit: GDPR-compliant, medical privacy protected
- What: Unique identifier preventing double-use of same proof
- How: Each prescription signature generates unique nullifier
- Why: Prevents fraud and double-signing
- Benefit: Each doctor can only sign once per prescription
- What: All verifications recorded on Flare blockchain
- How: Smart contract validates and stores all signatures
- Why: Immutable audit trail
- Benefit: Complete transparency, tamper-proof records
- What: Cryptographic proofs of prescription metadata
- How: Flare Data Connector verifies and attests data
- Why: Ensures data integrity and availability
- Benefit: Trustless metadata verification
All contracts deployed and verified on Flare Coston2 Testnet (Chain ID: 114)
PrescriptionHub (Main Application Contract)
- Address:
0x6fB0ce1685Fcfa6EeDdDFc4607a9ccbd5CBCC2E3 - Explorer: https://coston2-explorer.flare.network/address/0x6fB0ce1685Fcfa6EeDdDFc4607a9ccbd5CBCC2E3
- Purpose: Dual-doctor prescription verification with ZK proofs
- Functions:
createPrescription()- Doctor 1 creates prescriptionvalidatePrescription()- Doctor 2 validates prescriptionattestPrescription()- Store FDC attestation hashcanFillPrescription()- Pharmacy verificationrevokePrescription()- Patient revocation
- Events:
PrescriptionCreated(prescriptionId, hash, nullifier, patient)PrescriptionValidated(prescriptionId, nullifier)PrescriptionAttested(prescriptionId, fdcAttestationHash)
EVVM Core (Custom EVM Execution)
- Address:
0x37628b685c84a67cDd350D626a572857DFCcEC74 - Explorer: https://coston2-explorer.flare.network/address/0x37628b685c84a67cDd350D626a572857DFCcEC74
- Purpose: Enhanced EVM execution, custom chain support
- Name: EVVM
- Token: MATE (Mate token)
- Total Supply: 96 tokens
- Era Tokens: 32 per era
- Features:
- Gasless transactions (future implementation)
- Custom chain support
- Enhanced transaction processing
- Integration with staking and treasury
Staking Contract
- Address:
0x039F84BaF64F7cE5C274cDd11A800ACC7347A809 - Explorer: https://coston2-explorer.flare.network/address/0x039F84BaF64F7cE5C274cDd11A800ACC7347A809
- Purpose: EVVM staking mechanism
- Reward: 1,016,666,666.5 tokens
- Features:
- Validator staking
- Reward distribution
- Era management
Estimator Contract
- Address:
0x2F17029adff2b11C234f8Eab641A77E4629B1a40 - Explorer: https://coston2-explorer.flare.network/address/0x2F17029adff2b11C234f8Eab641A77E4629B1a40
- Purpose: Gas estimation for EVVM transactions
- Features:
- Transaction cost estimation
- Fee calculation
- Performance optimization
NameService Contract
- Address:
0xd9A361f89B8697D21E9b780a4A181D1A97a140Dc - Explorer: https://coston2-explorer.flare.network/address/0xd9A361f89B8697D21E9b780a4A181D1A97a140Dc
- Purpose: EVVM name resolution service
- Features:
- Human-readable names
- Address resolution
- Identity mapping
Treasury Contract
- Address:
0x9879fb6b778Ad9DB01CCDD1Df5fec00597F14eCF - Explorer: https://coston2-explorer.flare.network/address/0x9879fb6b778Ad9DB01CCDD1Df5fec00597F14eCF
- Purpose: EVVM treasury management
- Features:
- Fund management
- Reward distribution
- Financial operations
P2PSwap Contract
- Address:
0x3d55dE758aE4C767E63bB3A353cf4fB93ecdB19E - Explorer: https://coston2-explorer.flare.network/address/0x3d55dE758aE4C767E63bB3A353cf4fB93ecdB19E
- Purpose: Peer-to-peer token swapping
- Features:
- Decentralized exchange
- Token swaps
- Liquidity management
AdvancedStrings Library
- Address:
0xa5D085c7b479B04b4cB907ef2269048110C031eE - Explorer: https://coston2-explorer.flare.network/address/0xa5D085c7b479B04b4cB907ef2269048110C031eE
- Purpose: String manipulation utilities
- Features:
- Advanced string operations
- Helper functions
- Utility library
FDC Hub (Flare Data Connector)
- Address:
0x1c78A073E3BD2aCa4cc327d55FB0cD4f0549B55b - Explorer: https://coston2-explorer.flare.network/address/0x1c78A073E3BD2aCa4cc327d55FB0cD4f0549B55b
- Purpose: Flare Data Connector attestation verification
- Features:
- Metadata attestations
- Cryptographic proof verification
- Data availability layer
- Voting round finalization
Admin/GoldenFisher/Activator
- Address:
0x61643d97e10E681d5EA76218abC29036Ef3463Cc - Role: System administrator and governance
- Permissions: Contract management, system upgrades
Network: Flare Coston2 Testnet Chain ID: 114 RPC URL: https://coston2-api.flare.network/ext/C/rpc Explorer: https://coston2-explorer.flare.network Faucet: https://faucet.flare.network/coston2
Gas Used:
- EVVM Infrastructure: ~19,782,857 gas
- PrescriptionHub: ~973,343 gas
- Total Estimated: ~20,756,200 gas
Deployment Cost:
- EVVM Infrastructure: ~1.73 C2FLR
- PrescriptionHub: ~0.024 C2FLR
- Total: ~1.754 C2FLR
Deployment Date: November 23, 2024
Contract Interactions:
PrescriptionHub βββΊ EVVM βββΊ Staking
β
ββββΊ FDC Hub βββΊ Attestation Verification
β
ββββΊ NameService βββΊ Identity Resolution
β
ββββΊ Treasury βββΊ Fund Management
Coming soon: Full demonstration of the complete flow
What we'll show:
- Doctor 1 (Argentina) creates prescription
- Doctor 2 (USA) validates prescription
- FDC attestation process (~90 seconds)
- Pharmacy verification and dispensing
- Blockchain explorer showing all events
- Zero-knowledge proofs in action
- Smart contract development
- Dual-doctor ZK proof system
- FDC integration
- Basic frontend
- Deployment to Coston2
- IPFS metadata storage (replace localStorage)
- Mobile application (React Native)
- Prescription expiration logic
- Email/SMS notifications
- Mainnet deployment
- Pharmacy licensing verification
- Insurance integration
- Multi-language support (Spanish, Portuguese, etc.)
- Regulatory compliance (HIPAA, GDPR)
- Medical standards integration (ICD-10)
- Support for more countries
- Integration with EHR systems
- Real-time prescription tracking
- Analytics dashboard
- Mobile doctor verification
- Telemedicine integration
Contributions welcome! Please:
- Fork the repository
- Create feature branch (
git checkout -b feature/amazing) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing) - Open Pull Request
- Follow TypeScript best practices
- Write comprehensive tests
- Document all functions
- Maintain security standards
- Update README for new features
MIT License - see LICENSE file
- Flare Network - For infrastructure and FDC technology
- **EVVM ** - For EVVM infrastructure and technology
- Semaphore Protocol - For zero-knowledge proof system
- OpenZeppelin - For smart contract libraries
- Reown (WalletConnect) - For wallet integration
- Next.js Team - For the amazing React framework
If this project helped you, please give it a β!
- Smart Contracts: 1 (PrescriptionHub)
- Lines of Code: ~3,000+
- Integrations: 3 (EVVM, FDC, Semaphore)
- Frontend Pages: 4 (Doctor, Validate, Pharmacy, Home)
- Zero-Knowledge Proofs: β (unlimited privacy-preserving signatures)
Built with β€οΈ for the ETH Global Hackathon
Enabling trustless international healthcare through zero-knowledge proofs and decentralized verification
Ready to deploy. Ready to scale. Ready to change healthcare. π
Β© 2024 TravelScript. All rights reserved.