> ## 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](/v2/workers/off-chain/dvn-technical-reference#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.
   </Tip>

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.
   </Tip>
