Veritas: Keeping A Risk Score True As Copies Appear

Veritas: Keeping A Risk Score True As Copies Appear

Veritas was the sixth and last of the projects in our look at the UHI9 hookathon, and it puts a reactive contract to a use none of the others needed: keeping a stored number true after the thing it measures has quietly changed. The full project lives on GitHub, though the repository is private, so you may need to request access from the owner. The project's website is here

Veritas is a Uniswap v4 hook for pools of tokenized content, a photo or some other piece of media that someone has registered on-chain and opened a pool around. It prices a risk that ordinary pools ignore. As copies and near-duplicates of that content spread, the original loses the scarcity its value rests on, and the liquidity providers in its pool (the people who deposit the two tokens so others can trade between them) are the ones left holding that loss. Veritas attaches a risk score to each asset and feeds it into the pool's swap fee, so a riskier asset charges more and its providers are paid more to hold it. The interesting part, and the reason Reactive is involved, is when that risk actually changes.

A risk that arrives from somewhere else

To an ordinary automated market maker, a pool holding a one-of-a-kind photo looks exactly like a pool holding one of ten thousand identical copies. It can’t see scarcity, so it can’t price the loss that comes when scarcity fades. As duplicates multiply, the content's price drifts, and providers eat the difference as impermanent loss, the gap that opens up for a liquidity provider when the price moves and they end up worse off than if they had simply held the two tokens. Veritas measures how diluted a piece of content is and folds that into a single risk score, which the pool's fee then tracks.

Here is the part a hook can’t handle on its own. A piece of content's dilution does not change because of anything that content or its pool does. It changes when someone, somewhere else, registers a near-duplicate. Attest an original photo today (register it on-chain along with a fingerprint of the image) and its duplicate count is zero. Next week a near-copy of it gets attested, and the original is suddenly less unique than it was, through no event of its own. Nothing in its pool has traded, so its hook has not run, and no one has any reason to send a transaction that goes back and updates the original's record. The number that is supposed to stand for its risk is now quietly wrong.

What the reactive contract watches

Every new piece of content is recorded in a contract on Unichain, the registry, which emits a `NewAttestation` event when it happens. Veritas's reactive contract, `DilutionMonitorRC`, lives on Reactive's Lasna testnet and subscribes to that event, every one of them, because any new attestation might turn out to be a duplicate of something already on file.

// Watch every NewAttestation the registry emits on the origin chain.
service.subscribe(
    originChainId, originRegistry, NEW_ATTESTATION_TOPIC_0,
    REACTIVE_IGNORE, REACTIVE_IGNORE, REACTIVE_IGNORE
);

Where the earlier projects in this series subscribed to events about a single pool, this one subscribes to the arrival of new content across the whole registry, because that is where the risk to the existing assets comes from.

The score the diagram calls DRS is the pool's dilution risk score: a single number between 0 and 1 for how exposed a piece of content is to being copied, and the value the pool's fee tracks. The on-chain duplicate count is one of its inputs, so the more near-duplicates a piece of content picks up, the higher its count, the higher its DRS, and the more its pool charges to compensate the providers. Keeping that count current as new duplicates appear is the whole purpose of the loop: the registry emits an attestation event, the reactive contract on Lasna hears it and forwards the new attestation's id, and a callback back on Unichain finds the existing near-duplicates and raises their counts.

From a new attestation to a repriced pool

When an attestation arrives, `react()` runs, and it does something deliberately small: it forwards the new attestation's id to a callback on the other chain, and nothing more. It does not go hunting for duplicates itself. A reactive contract runs in a constrained environment that can’t cheaply read the destination chain's stored fingerprints, so the comparison is left to the side that can do it well.

function react(LogRecord calldata log) external vmOnly {
    bytes32 attestationId = bytes32(log.topic_2);   // the new attestation's id

    // Hand the id to the callback on the destination chain; let it run the search.
    emit Callback(destinationChainId, callbackReceiver, CALLBACK_GAS_LIMIT,
        abi.encodeWithSignature("onDilution(address,bytes32)", address(0), attestationId));
}

On the destination the callback does the real work. It reads the new content's fingerprint, asks the registry for everything already on file that looks close enough to count as a near-duplicate, and raises the dilution count on each of those existing records.

function onDilution(address /* rvmId */, bytes32 triggerAttestationId) external authorizedSenderOnly {

    // read the new content's fingerprint, then find the near-duplicates already on-chain...
    AttestationRecord memory rec = registry.getRecord(triggerAttestationId);
    bytes32[] memory affected =
        registry.getNearDuplicates(rec.pHashFingerprint, rec.blockhashFingerprint, HAMMING_TAU);

    // ...and raise each affected asset's dilution count.
    for (uint256 i = 0; i < affected.length; i++) _tryIncrement(affected[i]);
}

It listens only to Reactive's official callback proxy, and the registry in turn accepts these increments only from this callback, so the single contract allowed to raise an asset's risk is the one at the end of this exact chain of custody. Raising the count is what moves the score: a higher dilution count lifts the risk score, and the pool reads that new score and charges a higher fee on its very next swap. The provider who was quietly exposed to a copy that showed up last week is now, without anyone lifting a finger, paid more to carry it. Each increment is wrapped so that one frozen or disputed record can’t block the rest of the batch.

About Reactive Network

Reactive Network is an EVM automation layer built around reactive contracts, event-driven smart contracts for cross-chain, on-chain automation. It runs on CometBFT consensus, providing instant finality and roughly 1-second block times while maintaining full EVM compatibility.

Reactive contracts subscribe to event logs across EVM chains and execute Solidity logic automatically when matching events occur, deciding autonomously when to send cross-chain callback transactions. This model supports conditional cross-chain state changes and continuous cross-chain workflows.

Website | Blog | X | Telegram | Discord | Docs

Build once — react everywhere!

Read more