> For the complete documentation index, see [llms.txt](https://canary-1.gitbook.io/canary/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://canary-1.gitbook.io/canary/integrate/direct-contract-calls.md).

# Integration guide: direct contract calls

For applications that do not use the toolbox, or non-EVM environments proxying through a relayer.

If your application does not use the LayerZero toolbox, or you are integrating from a non-EVM environment and proxying through a relayer, configure DVNs by calling `setConfig` directly on the LayerZero EndpointV2 contract.

## 1. Fetch the DVN addresses

DVN addresses differ per chain. A DVN has a different deployment address on every chain it operates on, so you cannot reuse an Ethereum address on Arbitrum, and each pathway needs its own address pair. Per-chain addresses are published in the LayerZero DVN address registry, filtered for Canary at [docs.layerzero.network/v2/deployments/dvn-addresses?dvns=Canary](https://docs.layerzero.network/v2/deployments/dvn-addresses?dvns=Canary).

## 2. Construct the ULN config

The ULN configuration uses `configType = 2`. It is ABI-encoded as a single `UlnConfig` struct before it is passed to `setConfig`.

{% code title="configure-dvns.js" %}

```javascript
import { ethers } from 'ethers'

const confirmations = 15 // Block confirmations on the source chain
const optionalDVNThreshold = 1

// DVN addresses MUST be sorted ascending.
// Swap in real per-chain addresses from the DVN address registry.
const requiredDVNs = [
    '0x_CANARY_DVN_ADDRESS',            // Canary
    '0x_LAYERZERO_LABS_DVN_ADDRESS',    // LayerZero Labs
    '0x_DEUTSCHE_TELEKOM_DVN_ADDRESS',  // Deutsche Telekom
].sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))

const optionalDVNs = [
    '0x_HORIZEN_DVN_ADDRESS',           // Horizen
    '0x_YOUR_CHOSEN_DVN_ADDRESS',       // Your choice, see the recommended list
].sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))

// Encode as one UlnConfig struct (a tuple), so it decodes onchain as (UlnConfig).
const ULN_CONFIG_TYPE =
    'tuple(uint64 confirmations, uint8 requiredDVNCount, uint8 optionalDVNCount, ' +
    'uint8 optionalDVNThreshold, address[] requiredDVNs, address[] optionalDVNs)'

const ulnConfig = ethers.utils.defaultAbiCoder.encode(
    [ULN_CONFIG_TYPE],
    [{
        confirmations,
        requiredDVNCount: requiredDVNs.length,
        optionalDVNCount: optionalDVNs.length,
        optionalDVNThreshold,
        requiredDVNs,
        optionalDVNs,
    }]
)

const CONFIG_TYPE_ULN = 2

const setConfigParam = {
    eid: DESTINATION_EID, // Endpoint ID of the remote chain
    configType: CONFIG_TYPE_ULN,
    config: ulnConfig,
}

// Apply to both Send and Receive libraries
await endpoint.setConfig(oappAddress, sendLibAddress, [setConfigParam])
await endpoint.setConfig(oappAddress, receiveLibAddress, [setConfigParam])
```

{% endcode %}

## 3. Repeat for every pathway, on both ends

Run `setConfig` once for each pathway your application uses, on both ends. On Chain A, configure the Send library for messages going to Chain B. On Chain B, configure the Receive library for messages coming from Chain A. Then mirror both for the reverse direction.

Mismatches between Send and Receive configurations are the most common source of stuck messages. If a message is accepted by your Send configuration on Chain A but does not match your Receive configuration on Chain B, it will never verify and users will see stalled transfers.

## 4. Verify before trusting

After setting the configuration, read it back with `getConfig` and decode it. Do not assume `setConfig` succeeded silently.

```solidity
bytes memory config = endpoint.getConfig(oappAddress, libAddress, destinationEid, 2);
UlnConfig memory decoded = abi.decode(config, (UlnConfig));
// Assert decoded.requiredDVNCount, decoded.optionalDVNCount,
// decoded.optionalDVNThreshold, and every address in
// decoded.requiredDVNs / decoded.optionalDVNs match your intent.
```
