> ## Documentation Index
> Fetch the complete documentation index at: https://docs.layerzero.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Build Decentralized Verifier Networks (DVNs)

> Technical guide for implementing and integrating a third-party DVN into the LayerZero V2 protocol, including fee quoting, event listening, and verification workflows.

This document contains a high level overview of how to implement and integrate a basic third party DVN into the LayerZero V2 protocol.

## Fee Quoting, Collection, and Withdrawal

DVN owners should implement and deploy a DVN contract on every chain they want to support. The contract must implement the `ILayerZeroDVN` interface, which specifies two core functions:

* **`assignJob`** - Called by the Message Library when a packet is sent, paying the DVN for verification
* **`getFee`** - Returns the fee for verifying a message to a specific destination

For the complete interface specification, data structures, and method signatures, see the [DVN Technical Reference](https://docs.layerzero.network/v2/workers/off-chain/dvn-technical-reference.md#ilayzerodvn).

If your DVN is responsible for a packet, the LayerZero Endpoint will call your DVN contract's `assignJob` function.

## Building a DVN

The DVN has one off-chain workflow:

1. The DVN first listens for the `PacketSent` event:

   ```solidity theme={null}
   PacketSent(
   bytes encodedPacket,
   bytes options,
   address sendLibrary)
   ```

   The packet has the following structure:

   ```solidity theme={null}
   struct Packet {
       uint64 nonce; // the nonce of the message in the pathway
       uint32 srcEid; // the source endpoint ID
       address sender; // the sender address
       uint32 dstEid; // the destination endpoint ID
       bytes32 receiver; // the receiving address
       bytes32 guid; // a global unique identifier
       bytes message; // the message payload
   }
   ```

   The encoded packet can be deserialized with the [`PacketSerializer`](https://github.com/LayerZero-Labs/monorepo/blob/a6c8758d436804f41db62d480f82cdb0690faaef/packages/layerzero-v2/utility/src/model/packet.ts#L29) and the option can be deserialized with the [`OptionSerializer`](https://github.com/LayerZero-Labs/monorepo/blob/a6c8758d436804f41db62d480f82cdb0690faaef/packages/layerzero-v2/utility/src/options/options.ts#L81).

2. After the `PacketSent` event, the `DVNFeePaid` event is how you know your DVN has been assigned to verify the packet's `payloadHash`.

   ```solidity theme={null}
   DVNFeePaid(
       address[] requiredDVNs,
       address[] optionalDVNs,
       uint256[] fees
   );
   ```

   > [!TIP]
   >
   > The `DVNFeePaid` event returns a list of **all** of the OApp's configured DVNs, so your workflow should filter your specific DVN address from the array to make sure your DVN has been paid.

3. After receiving the fee, your DVN should query the address of the MessageLib on the destination chain:

   ```solidity theme={null}
   getReceiveLibrary(
       _receiver,
       _dstEid
   );
   ```

4. After your DVN has retrieved the receive MessageLib, you should read the MessageLib configuration from it. In the configuration is the required block `confirmations` to wait before calling `verify` on the destination chain.

   ```solidity theme={null}
   function getUlnConfig(address _oapp, uint32 _remoteEid) public view returns (UlnConfig memory rtnConfig);
   ```

   This will return the `UlnConfig`, which you can use to read the number of `confirmations`:

   ```solidity theme={null}
   struct UlnConfig {
       uint64 confirmations;
       // ...
   ```

5. Your DVN should next do an idempotency check:

   ```solidity theme={null}
   ULN._verified(
       _dvn,
       _headerHash,
       _payloadHash,
       _requiredConfirmation
   );
   ```

   This returns a boolean value:

   * If the state is `true`, then your idempotency check indicates that you already verified this packet. You can terminate your DVN workflow.

   * If the state is `false`, then you must call `ULN.verify`:

   ```solidity theme={null}
   ULN._verify(
       _packetHeader,
       _payloadHash,
       _confirmations
   );
   ```

   > [!TIP]
   >
   > To know your workflow has successfully fulfilled its obligation, your DVN should perform an idempotency check at the end of the DVN workflow.
