Skip to content

passionate-dev7/veil

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Veil Protocol

On-chain payroll is public by default. Veil makes it private without breaking auditability.

Chainlink Convergence 2026 — Privacy Track


The Problem

Every Gnosis Safe payroll transaction is visible on Etherscan the moment it lands. Open any DAO multisig — Uniswap, Optimism Collective, Gitcoin — and you can read exactly who got paid, how much, and when. The recipient's wallet address links to their entire transaction history. Their landlord, their next employer, and every phishing bot on the network can see it too.

This is not a hypothetical. DAO contributors have faced targeted phishing and physical threats tied directly to on-chain salary data. There is no existing payroll tool for Web3 — Utopia, Coordinape, Superfluid — that addresses this. They all settle on a public chain, in the clear.

Labor law in most jurisdictions treats payroll data as confidential. Web3 payroll is structurally non-compliant by design.


What Veil Does

  • Executes payroll privately. The CRE workflow fetches recipient addresses and amounts from an off-chain HR API via Confidential HTTP (TEE-encrypted — node operators cannot read the response). Transfers go through Chainlink ACE with hide-sender flag and shielded recipient addresses. Individual amounts never appear on the public chain.
  • Enforces budget on-chain without exposing individual payments. VeilVault.sol tracks monthly spend limits, batch lifecycle (PENDING → EXECUTING → COMPLETED), and role-based access. The public chain sees aggregate totals only.
  • Proves correctness without revealing details. After each batch, the CRE workflow submits a PrivacyAttestation to the vault: a Merkle root over all (recipient, amount) leaves, a sum-check hash, and an IPFS pointer to an encrypted audit report. Any employee can prove they were paid — without seeing anyone else's amount.

6 Chainlink Capabilities

Capability How It's Used Code Reference
CRE (Runtime Environment) Cron-triggered workflow orchestrates the full 7-step payroll pipeline. Reads contract state, writes batch lifecycle transitions, coordinates all other capabilities. workflow/main.tsonCron()
CRE Secrets runtime.getSecret({ id: 'TREASURY_PRIVATE_KEY' }) fetches the treasury signing key at runtime inside the TEE. Never stored in config. Node operators cannot see it. workflow/main.tsprivateKey
Confidential HTTP The HTTPClient callback wraps both the payroll API fetch and all ACE transfer requests. The full envelope — URL, headers, request body, response body — is encrypted. Recipient addresses and amounts are invisible to the Chainlink network. workflow/main.tsexecutePayroll()
Chainlink ACE (Confidential Compute) Private token transfers with hide-sender flag, EIP-712 authorization, and shielded address generation per recipient. Transfers do not appear as individual on-chain events. workflow/main.tsexecutePayroll(), signACE()
Data Feeds latestRoundData() on ETH/USD and LINK/USD feeds at LAST_FINALIZED_BLOCK_NUMBER. Used to convert payroll amounts to USD for budget validation before execution. workflow/main.ts — Step 2
CCIP Recipients with a chain field in payroll data are routed cross-chain. executePayroll() collects them as crossChainRecipients; onCron() calls VeilVault.sendCrossChainPayroll(batchId, chainSelector, recipient, token, amount) per recipient. Config: ccipDestinations with Ethereum Sepolia chain selector 16015286601757825753. workflow/main.ts — Step 5c, VeilVault.sol:378

Privacy Model

What Goes On-Chain (Public) What Stays Off-Chain or Sealed
Batch ID, batch type (PAYROLL / GRANT / TREASURY_OP), recipient count, total amount, memo Individual recipient addresses
Batch status transitions: PENDING, EXECUTING, COMPLETED Individual payment amounts
Merkle root of all (recipient, amount) leaves Payroll API credentials (CRE Secrets, TEE)
Sum-check hash: keccak256(sum_of_parts, totalAmount) Full payroll API response (Confidential HTTP)
IPFS hash of encrypted audit report Plaintext audit report (treasurer-only decryption key)
Monthly budget consumed (aggregate) Which wallet received which amount

Architecture

  Cron Trigger
       |
       v
  STEP 1: Read pending batches from VeilVault (EVM read, Base Sepolia)
       |
       v
  STEP 2: Fetch ETH/USD + LINK/USD from Chainlink Data Feeds
       |
       v
  STEP 3: Confidential HTTP envelope opens
  |      |
  |      +-- GET payroll API --> recipient list + amounts (encrypted in transit)
  |      |
  |      +-- ACE: check treasury balance (EIP-712 signed, hide-sender)
  |      |
  |      +-- For each recipient:
  |           +-- ACE: generate shielded address
  |           +-- ACE: private transfer with hide-sender flag
  |
  Confidential HTTP envelope closes (node operators saw nothing)
       |
       v
  STEP 4: Mark batch EXECUTING on VeilVault (EVM write, onlyCRE)
       |
       v
  STEP 5: Validate batch total against on-chain monthly budget
       |
       v
  STEP 5c: CCIP routing -- for recipients with chain field, call sendCrossChainPayroll()
       |    (Ethereum Sepolia selector: 16015286601757825753)
       v
  STEP 6: completeBatch() on VeilVault -- updates budget, emits aggregate event
       |
       v
  STEP 7: submitAttestation() -- Merkle root + sum-check hash + IPFS audit hash

Smart Contracts

VeilVault — Base Sepolia

0x42118F942332f6cAEE0aA768bB741A2f1eb65204

View on BaseScan

For VaultFactory deployment details, see the deployment section in contracts/script/Deploy.s.sol.

Key functions:

Function Access What It Does
submitBatch() Payroll Admin Registers a new batch with total amount + data hash of encrypted off-chain details
markBatchExecuting() CRE workflow only Locks batch before transfers begin
completeBatch() CRE workflow only Records actual amount spent, updates monthly budget
submitAttestation() CRE workflow only Stores Merkle root + sum-check hash + IPFS audit pointer
verifyPaymentInclusion() Anyone Verifies a single payment against the stored Merkle root
sendCrossChainPayroll() CRE workflow only CCIP cross-chain distribution (implemented, config-ready)

Role hierarchy: Owner > Treasury Manager > Payroll Admin > CRE Workflow (contract-to-contract only).


Employee Payment Verification

This is the core privacy-vs-accountability tradeoff, resolved on-chain.

After ACE transfers complete, the CRE workflow builds a Merkle tree where each leaf is:

leaf = keccak256(abi.encodePacked(recipientAddress, amount))

The root is stored in VeilVault via submitAttestation(). The sum-check hash keccak256(abi.encode(sum_of_parts, totalAmount)) proves no funds were skimmed or misrouted — the sum of all individual payments equals the batch total declared on-chain.

An employee who wants to verify they were paid calls:

vault.verifyPaymentInclusion(
    batchId,       // which batch
    myAddress,     // my wallet address
    myAmount,      // amount I claim to have received
    merkleProof    // proof path provided by the treasurer
)

This returns true and emits PaymentVerified(batchId, recipient, amount) if the proof is valid.

What this achieves: the employee proves inclusion without the contract revealing any other leaf. No other employee's address or amount is exposed. The treasurer provides individual proofs off-band (e.g., via encrypted email). The DAO can publicly assert "all 12 contributors were paid" and any contributor can independently verify their own payment — on-chain, trustlessly — without the full payment list ever being public.

Dispute resolution becomes possible: if a contributor claims non-payment, the treasurer provides a Merkle proof. If no valid proof exists, the on-chain attestation proves the batch was processed without that recipient.


Quick Start

Prerequisites: Bun, Foundry, CRE CLI

# Clone
git clone https://github.com/your-org/xchain-agents
cd veil

# Install workflow dependencies
cd workflow && bun install

# Build contracts
cd ../contracts && forge build

# Run tests (32/32 pass)
forge test -vv

# Simulate CRE workflow
cd ..
cre workflow simulate workflow -T staging-settings

# Run frontend
cd frontend && bun install && bun run dev

Deploy to Base Sepolia:

cd contracts
PRIVATE_KEY=0x... forge script script/Deploy.s.sol:DeployVeilVault \
  --rpc-url https://sepolia.base.org --broadcast --legacy

Test Coverage

forge test -vv

Running 32 tests for test/VeilVault.t.sol:VeilVaultTest
[PASS] testConstructor()
[PASS] testSubmitBatch()
[PASS] testSubmitBatchAsAdmin()
[PASS] testSubmitBatchRevertUnauthorized()
[PASS] testSubmitBatchRevertExceedsBudget()
[PASS] testSubmitBatchRevertZeroRecipients()
[PASS] testSubmitBatchRevertZeroAmount()
[PASS] testMarkBatchExecuting()
[PASS] testMarkBatchExecutingRevertNotCRE()
[PASS] testCompleteBatch()
[PASS] testCompleteBatchRevertNotExecuting()
[PASS] testCancelBatch()
[PASS] testCancelBatchRevertNotPending()
[PASS] testBudgetTracking()
[PASS] testBudgetResetsAfterMonth()
[PASS] testBudgetBlocksOverspend()
[PASS] testGetPendingBatches()
[PASS] testTotalBatches()
[PASS] testSetMonthlyBudget()
[PASS] testSetMonthlyBudgetRevertNotOwner()
[PASS] testSetTreasuryManager()
[PASS] testSetCREWorkflow()
[PASS] testFullPayrollCycle()
[PASS] testGrantDistributionCycle()
[PASS] testTreasuryOpCycle()
[PASS] testSubmitAttestation()
[PASS] testAttestationRevertNotCompleted()
[PASS] testAttestationRevertDuplicate()
[PASS] testAttestationRevertNotCRE()
[PASS] testVerifyPaymentInclusion()
[PASS] testVerifyPaymentInclusionInvalid()
[PASS] testFullCycleWithAttestation()

32 passed, 0 failed

Tech Stack

Layer Stack
Workflow TypeScript, @chainlink/cre-sdk ^1.1.2, Bun
Smart Contracts Solidity 0.8.24, Foundry
ACE signing @noble/curves (secp256k1, EIP-712)
ABI encoding viem
Config validation zod
Frontend Next.js 15, wagmi v3, viem, Tailwind CSS

Hackathon Track

Chainlink Convergence 2026 — Privacy Track

Veil is a submission for the privacy track. The core claim: six Chainlink capabilities (CRE, CRE Secrets, Confidential HTTP, ACE, Data Feeds, CCIP) can be composed into a system where a DAO pays its contributors privately, proves correctness on-chain, routes cross-chain payments automatically, and gives every recipient a way to verify their own payment — without a trusted intermediary and without making salary data public.

The demo scenario is employee payment verification: a contributor to "Veil Demo DAO" receives a Merkle proof from the treasurer after the March 2026 payroll batch completes. They call verifyPaymentInclusion() on Base Sepolia and get an on-chain confirmation they were paid, with no other salary data exposed.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors