v0.1.0-beta

Scoring Model

Veil builds a behavioral credit score from events submitted by registered issuers. Midnight keeps the score and accumulators private, while CKB stores only the user's immutable Veil Identity DOB anchor. Credit decisions expose a band and policy limits, never the raw score.

Overview

The scoring model is intentionally behavioral rather than balance-based. A wallet with large holdings but a poor repayment history is less trustworthy than a smaller wallet with a consistent on-time record. Veil captures this by accumulating behavioral events over time and weighting them according to a configurable formula.

The score lives entirely in private state — it is never stored in plaintext on any public ledger. Only a ZK commitment to the score is published on-chain. When a protocol requests a credit decision, the user authorizes that request with their CKB wallet and Veil returns a decision band without revealing the raw score value.

Issuer-gated data
Only registered issuers — DeFi protocols approved by the Veil admin — can submit scoring events. This gating prevents unverified sources from polluting the credit data. Contact the Veil team to register your protocol as an issuer.

Issuers & Data Providers

An issuer is a DeFi protocol that has been approved to submit behavioral data to Veil. Issuers are registered on-chain by the Veil admin via Admin_addIssuer, which derives and returns the issuer's public key (issuerPk). This key must be included in every scoring event the issuer submits.

Issuers fulfill two roles:

  • Data provider — submit repayment, liquidation, protocol usage, and debt state events tied to a user's Veil ID.
  • Verifier — call the credit decision endpoint to check the user's current band and lending limits after the user authorizes the request.

Issuers never learn the real identity of the users they track. All interactions use the user's Veil ID (userPk) — a deterministic, anonymous public key.

Scoring Events

Issuers submit behavioral events via four dedicated endpoints. Each event is processed by a ZK circuit that validates the issuer's authorization, enforces replay protection, and updates the user's private score accumulator.

Event monotonicity
The eventEpoch field must be equal to or greater than the epoch of the last event submitted for that user. Backdated events are rejected by the contract to prevent retroactive score manipulation.

Repayment Events

Submit whenever a user repays a loan. This is the highest-weight signal in the scoring model.

bashPOST /scoring-events/repayments
curl -X POST https://{VEIL_API}/scoring-events/repayments \
  -H "Content-Type: application/json" \
  -d '{
    "userPk": "0xabc123...",
    "issuerPk": "0xdef456...",
    "paidOnTimeFlag": 1,
    "amountWeight": 1000,
    "eventEpoch": 3,
    "eventId": "0x..."
  }'
FieldTypeDescription
userPkBytes (hex)The user's Veil ID
issuerPkBytes (hex)Your registered issuer public key
paidOnTimeFlag1 | 01 = paid on time, 0 = late
amountWeightBigIntRelative loan size weight (e.g. 1000 for a normalized unit)
eventEpochBigIntProtocol epoch at which the event occurred
eventIdBytes (hex, optional)Unique event identifier for replay protection. Auto-generated if omitted.

Liquidation Events

Submit when a user's position is liquidated. Severity determines the penalty magnitude.

bashPOST /scoring-events/liquidations
curl -X POST https://{VEIL_API}/scoring-events/liquidations \
  -H "Content-Type: application/json" \
  -d '{
    "userPk": "0xabc123...",
    "issuerPk": "0xdef456...",
    "severity": 2,
    "eventEpoch": 3,
    "eventId": "0x..."
  }'
severityMeaningScore impact
1Minor liquidation — small position, managed outcomeLow penalty
2Moderate liquidation — significant positionMedium penalty
3Severe liquidation — large or full position lossHigh penalty

Protocol Usage Events

Submit each time a user meaningfully interacts with your protocol (e.g. takes a position, provides liquidity). Diversity of protocol usage is a positive scoring signal — but each unique (user, protocol) pair is counted only once, preventing inflation.

FieldTypeDescription
userPkBytes (hex)The user's Veil ID
issuerPkBytes (hex)Your registered issuer public key
protocolIdBytes (hex)A stable identifier for your protocol
eventEpochBigIntProtocol epoch at which the interaction occurred

Debt State Events

Periodic debt state snapshots capture a user's current risk exposure. The riskBand (0–3) encodes collateralization quality, and activeDebtFlag indicates whether the user currently holds open debt.

FieldTypeDescription
activeDebtFlag0 | 11 = user has active debt, 0 = no active debt
riskBand0–30 = healthy, 3 = high-risk collateral position

Score Computation

The score is derived from private score accumulators updated by issuer-submitted events. The current implementation records the accumulator and score commitments on Midnight, then derives credit decisions from the private state associated with the user's Veil ID. The formula combines positive behavioral signals with penalty deductions:

Core Formula
rawScore = baseScore + behaviorScorepenaltyScore
score = clamp(rawScore, 0, maxScore)
Behavior Score positive signals
repaymentRatio × repaymentWeight
+ repayment history
distinctProtocols × protocolWeight
+ cross-protocol breadth
epochsActive × tenureWeight
+ on-chain tenure
Penalty Score risk deductions
liquidationPts × liquidationWeight
− liquidation history
activeDebtFlag × activeDebtPenalty
− open debt exposure
riskBand × riskBandWeight
− collateral risk level (0–3)
repaymentRatio = (onTimeRepayments / totalRepayments) × scale// verified in-circuit via remainder proof
ParameterDefaultDescription
baseScore350Starting score for all users
maxScore900Score ceiling
repaymentWeight2Multiplier on repayment ratio
protocolWeight10Per unique protocol interaction
tenureWeight1Per active epoch
liquidationWeight3Penalty multiplier per liquidation point
activeDebtPenalty5Flat penalty when user holds active debt
riskBandWeight5Penalty per risk band level (0–3)
On-chain safety invariants
The contract enforces event monotonicity (no backdating), replay protection via domain-tagged event hashes, commitment validation against on-chain Merkle trees, and score arithmetic underflow/overflow assertions before any value is stored.

Trust Tiers

Trust tiers are returned in the credit decision response. They are derived from the current private score and should be treated as policy bands rather than public score disclosures:

TierScore profileAccess profile
UnrankedNo score entry, insufficient history, or low current scoreNo privileged access; standard over-collateralized terms
BronzeBasic positive behaviorBasic credit access; reduced collateral requirements
SilverConsistent repayment and moderate activityModerate benefit tier; improved LTV and rate adjustments
GoldStrong repayment behavior and low risk exposureHigh-trust tier; preferential rates, higher LTV limits
PlatinumBest current risk profileMaximum trust tier; undercollateralized borrowing, fee waivers

Protocols consuming Veil decisions should handle all tiers, including Unranked. They should also use the returned maxLtvBps and riskPremiumBpsrather than hard-coding their own interpretation of the band.

Veil Identity DOB

Veil no longer mints Proof-of-Trustworthiness NFTs on Midnight. The public identity anchor is a user-minted Veil Identity DOB on CKB using Spore. The DOB stores only stable identity-anchor metadata: veilIdHash, the owner CKB lock hash, the Midnight network, the backend-deployed Midnight contract address, and a version string.

Prepare
The backend creates a DOB mint intent after the Midnight score entry exists. The intent contains stable public metadata only.
Mint
The user's CKB wallet constructs, signs, funds, and submits the Spore transaction. The backend does not pay CKB capacity or fees.
Record
After minting, the app records the Spore ID and transaction hash with the backend for later lookup.
Verify
Credit decisions verify the DOB content, veil_sbt_lock script, owner lock hash, and CKB wallet authorization signature.
Immutable public metadata only
Do not put mutable scores, changing commitments, raw identity, behavioral history, or private state in the DOB. The DOB is a public cross-chain anchor, not the score itself.

Epoch System

Veil scoring events carry an eventEpochsupplied by the issuer/backend. The contract enforces monotonicity so a user's event stream cannot be backdated. Epochs are used to:

  • Enforce event monotonicity (events must not be backdated)
  • Compute epochsActive (tenure contribution to score)
  • Keep score updates ordered across issuer submissions

Privacy Invariants

The Veil scoring model is designed so that no participant — not even the Veil backend — can reconstruct a user's score from public data:

  • Raw score never disclosed: Only ZK commitments (Merkle tree roots) are published on-chain. The actual numeric value stays in private state.
  • Decision returns a band: Integrators learn only the decision band, LTV limit, risk premium, and validity timestamp — not the raw score or private inputs.
  • Replay-protected challenges: Each verification call requires a fresh challenge that expires in 60 seconds and cannot be reused.
  • Wallet authorization: The user signs the canonical credit decision message with their CKB wallet. Their Midnight secret key never leaves their machine and is never sent to a backend endpoint.