> ## 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.

# Deploying an OFT on Canton

> Connect an existing CIP-0056 token on Canton to LayerZero with an OFT adapter, wire it to an EVM chain, and see which steps you complete with LayerZero Labs.

This page lists every step to make an existing CIP-0056 token on Canton an [Omnichain Fungible Token (OFT)](https://docs.layerzero.network/v2/concepts/applications/oft-standard.md) with an OFT adapter, and to wire it to an EVM chain. It covers the Canton side, the EVM side, and a first transfer in each direction.

> [!NOTE]
>
> LayerZero on Canton is not yet open for self-service integrations. The Canton contract packages and deployment tooling are not public. Steps that depend on LayerZero start with "Work with LayerZero Labs" and say what happens in that step. To start an integration, [contact the LayerZero team](https://layerzeronetwork.typeform.com/to/U9hMgxf1).

Read [Getting Started](https://docs.layerzero.network/v2/developers/canton/getting-started.md) and [Technical Overview](https://docs.layerzero.network/v2/developers/canton/technical-overview.md) first. This page uses their terms: parties, participant nodes, signatories, disclosed contracts, and holdings.

## How an OFT Works on Canton

On Canton, LayerZero connects an existing [CIP-0056](https://github.com/global-synchronizer-foundation/cips/blob/main/cip-0056/cip-0056.md) token, for example a token issued through Digital Asset's registry, with an **OFT adapter**. The adapter is a set of Daml contracts. The **OApp admin** signs them. It is usually the asset issuer. For Canton Coin, it is the `ccadapter` party that LayerZero Labs administers (see [Parties Involved](#parties-involved)). The adapter reaches the LayerZero [Virtual Endpoint Rollup (VER)](https://docs.layerzero.network/v2/developers/canton/protocol-overview.md#the-virtual-endpoint-rollup-ver) through request contracts on the ledger.

### Adapter Models

The LayerZero Canton packages support two adapters:

| Adapter | When to use it | What happens on send | What happens on receive |
| - | - | - | - |
| **Burn/mint adapter (`BurnMintAdapter`)** | Your CIP-0056 token supports burn and mint | The sent amount is burned through the token's burn/mint factory when the send is submitted | The amount is minted to the mint escrow party, which then sends the receiver a CIP-0056 transfer instruction |
| **Lock/unlock adapter (`LockUnlockAdapter`)** | You do not want to mint or burn the token on Canton | The sent amount moves into a custody party | The custody party sends the receiver a CIP-0056 transfer instruction |

With both adapters, the receiver gets a CIP-0056 transfer instruction. If the token's transfer rules require it, the receiver accepts the instruction in a separate transaction, usually through its wallet. The instruction expires after 24 hours, and the tokens return to the custody or mint escrow party. LayerZero does not resend an expired instruction automatically. To have the tokens delivered again, [contact the LayerZero team](https://layerzeronetwork.typeform.com/to/U9hMgxf1). For Canton Coin, a receiver with a transfer preapproval gets the tokens without a separate accept.

The burn/mint adapter has a second signatory, a mint escrow party. The lock/unlock adapter has a second signatory, the custody party that holds locked assets. Both must be different from the OApp admin.

A burn/mint adapter can burn and mint only through a burn/mint factory that the OApp admin controls. If the token's instrument admin is a different party, the instrument admin creates a `BurnMintDelegate` contract for the token. This contract gives the OApp admin burn and mint rights for that one instrument. The instrument admin can revoke these rights by archiving the contract.

### Parties Involved

| Party | Operated by | Role |
| - | - | - |
| OApp admin | Usually you, the asset issuer. For Canton Coin, the `ccadapter` party that LayerZero Labs administers | Signatory on the adapter, its configuration, the registry, and the rate limiter |
| Custody party or mint escrow party | As agreed in Step 1 | Second signatory on the adapter. Holds locked tokens (lock/unlock) or minted tokens before they go to the receiver (burn/mint) |
| Instrument admin | The party that administers the token on Canton | Burn/mint only, when it is not the OApp admin: signs the `BurnMintDelegate` |
| Fee deposit party | You | Receives the optional fee on each send |
| `lzowner` (OApp gateway, request handler) | LayerZero | Observer on your OApp contracts; signatory on request contracts; holds request fees in escrow; accepts or rejects requests |
| Protocol treasury | LayerZero | Signatory on request contracts; receives request fees |
| Executor | LayerZero | Delivers inbound messages into Canton and settles pending callbacks |
| Sender and receiver | Your users, through their wallets | Hold the token and initiate transfers |

### Decimals

The adapter's configuration contract (`AdapterConfig` for lock/unlock, `BurnMintAdapterConfig` for burn/mint) stores `localDecimals` (at most 10 on Canton) and `sharedDecimals`. As on other chains, the amount in a LayerZero message uses shared decimals. Pick a `sharedDecimals` value that every chain in your mesh supports. The [OFT standard](https://docs.layerzero.network/v2/concepts/applications/oft-standard.md) explains shared decimals.

## Prerequisites

1. **A participant node for your parties.** Run your own validator node, or use a party hosted on another operator's node. A validator node needs a [Super Validator sponsor](https://docs.dev.sync.global/validator_operator/validator_onboarding.html) to join the Global Synchronizer.
2. **Ledger API access** to that participant node, with rights to submit commands as your parties.
3. **Parties.** Allocate the OApp admin party and a fee deposit party on your participant node. Allocate the custody or mint escrow party too, unless you agree in Step 1 that another operator runs it. See [Manage Daml Parties](https://docs.canton.network/appdev/deep-dives/manage-daml-parties).
4. **An existing [CIP-0056](https://github.com/global-synchronizer-foundation/cips/blob/main/cip-0056/cip-0056.md) token.** Choose the lock/unlock or the burn/mint adapter. For the burn/mint adapter, the token must have a CIP-0056 burn/mint factory.
5. **Amulet (Canton Coin)** on your parties, to pay for traffic, endpoint request fees, and registry fees.
6. **A Canton 3.x environment.** The LayerZero packages target Canton 3.x and the Daml 3.x SDK.
7. **An EVM deployer** for the remote side, set up as in the [EVM OFT quickstart](https://docs.layerzero.network/v2/developers/evm/oft/quickstart.md).

## Step 1: Agree on the Integration

Work with LayerZero Labs to start the integration. In this step, you and LayerZero agree on:

* The adapter model and the networks: LayerZero testnet (Canton DevNet) first, then mainnet
* The EVM chains to connect
* Who operates which parties, including the mint escrow or custody party for an adapter
* The send and receive security settings (DVNs and confirmations)

## Step 2: Get the LayerZero Package Set and Protocol References

Work with LayerZero Labs to receive these items:

* **The LayerZero DAR packages.** See [LayerZero Packages](https://docs.layerzero.network/v2/developers/canton/technical-overview.md#layerzero-packages).
* **The protocol references** that your contracts point to. These are the `lzowner` party, which observes your OApp and handles its requests, the request factory contract, and the endpoint address that the adapter configuration stores.
* **The disclosures** for the LayerZero-signed contracts that your transactions use, such as the request factory. Your participant node cannot see these contracts, so each submission must attach them as [disclosed contracts](https://docs.canton.network/appdev/deep-dives/explicit-contract-disclosure).

## Step 3: Upload and Vet the Packages

Upload the DAR packages to your participant node. Canton vets a package as part of the upload by default. See [Manage Daml Packages](https://docs.canton.network/appdev/modules/m5-manage-daml-packages).

Every participant node that takes part in a transaction with your token must vet the same packages. This includes the participant nodes of your users' wallets. Plan this with your wallet providers before launch.

## Step 4: Create the Adapter Contracts on Canton

Submit these commands as the OApp admin. None of these contracts needs a signature from LayerZero. Each contract lists `lzowner` (from Step 2) as an observer when you create it. This lets LayerZero see your contracts, so it can process your requests and provide the disclosures that senders and the executor need.

1. **Burn/mint delegate (burn/mint adapter only).** If the token's instrument admin is not the OApp admin, the instrument admin creates a `BurnMintDelegate` for the token. It names the OApp admin as the delegate, the token's burn/mint factory, and `lzowner` as `oappGateway`.
2. **Adapter.** Create `LockUnlockAdapter` or `BurnMintAdapter` with the OApp ID and `lzowner` as `oappGateway`. The OApp ID is the OApp admin party and an ID string that you choose. The custody party (lock/unlock) or the mint escrow party (burn/mint) is the second signatory, so it must also authorize this command.
3. **Configuration.** Create `AdapterConfig` (lock/unlock) or `BurnMintAdapterConfig` (burn/mint). It holds:
   * the OApp ID and the token's instrument ID
   * `localDecimals` and `sharedDecimals`
   * the fee deposit party and the fee in basis points per destination EID
   * the request factory and the endpoint address from Step 2
   * the rate limiter configuration (rate limiting can be disabled)
   * empty maps for peers and enforced options, which you set in Step 6
   * the observers of the configuration, including `lzowner`
4. **Receiver registry.** Create a `Registry` and its `RegistryConfig`. On receive, the adapter uses the registry to turn the 32-byte receiver in the message into a Canton party. The configuration sets an optional registration fee and a maximum number of entries.
5. **Access control and rate limiter state.** Create an `AccessControl` contract if you want to give roles to other parties, for example a manager or a fee manager. Without it, only the OApp admin can run administrative choices. Create a `RateLimiterState` contract if you use rate limits.

> [!NOTE]
>
> Contract IDs change when you update a contract. Each configuration choice in Step 6 archives the adapter configuration and creates a new one. Read the current contract ID from the ledger after each change.

## Step 5: Set the Endpoint Configuration

On Canton, endpoint settings are requests, not direct calls. For each setting, the OApp admin exercises `OApp_CreateRequest` on the adapter. The request carries the endpoint call and pays the request fee in Amulet. VER processes the request, and the `lzowner` party accepts it.

Submit one request for each of these endpoint calls:

| Endpoint call | What it sets |
| - | - |
| `setSendLibrary` | The send library for each destination EID |
| `setReceiveLibrary` | The receive library for each source EID |
| `setSendConfig` | The DVNs, confirmations, and executor for sends to each EID |
| `setReceiveConfig` | The DVNs and confirmations for receives from each EID |
| `setDelegate` | The delegate for your OApp, as `setDelegate` does on EVM chains |
| `setInitializablePath` | Marks the path from each remote peer as initializable. On a path that has never delivered a message, VER rejects the executor's commit of the verification unless the path is marked. Without this call, messages from that peer into Canton cannot be delivered. Submit it for each remote EID and peer that you will set in Step 6. |

Work with LayerZero Labs to get the current request fee and to agree on the values. Hold enough Amulet on the OApp admin for every request. Do not submit a second request for the same setting while the first one is still pending.

**DVNs on Canton.** Canton DVNs are deployed once per DVN provider, at the protocol level, as on other chains. You do not deploy DVN contracts for your OApp. You choose DVNs in `setSendConfig` and `setReceiveConfig`. For the DVNs that verify Canton Coin messages on Canton mainnet, see [DVN Providers](https://docs.layerzero.network/v2/deployments/dvn-addresses.md?chains=canton). Use the DVN addresses that LayerZero Labs confirms in Step 1.

## Step 6: Configure the Adapter on Canton

Exercise these choices on the adapter configuration as the OApp admin, or as a party with the required role. They do not go through VER and do not need a LayerZero signature.

| Choice | What it sets |
| - | - |
| `IOAppConfig_SetPeer` | The peer for each remote EID: the remote OFT address as a 32-byte lowercase hex value without a `0x` prefix. For an EVM OFT, left-pad the 20-byte address to 32 bytes. An all-zero value removes the peer. For each peer, also submit `setInitializablePath` (Step 5). |
| `IOAppConfig_SetEnforcedOptions` | Options that every send to an EID must include, per message type, for example the gas limit for `lzReceive` on the EVM chain |
| `IOAppConfig_SetFeeBps` | The fee in basis points per destination EID (fee manager role) |

Set rate limits with the rate limiter choices on the adapter configuration (rate limiter manager role). The `RateLimiterState` contract tracks usage.

## Step 7: Deploy and Wire the EVM Side

Deploy an OFT on the EVM chain with the standard tooling, as in the [EVM OFT quickstart](https://docs.layerzero.network/v2/developers/evm/oft/quickstart.md). Then wire it to Canton:

1. **Set the peer.** Call `setPeer` on the EVM OFT with the Canton EID (`30567` for mainnet, `40567` for LayerZero testnet on Canton DevNet) and the adapter's 32-byte OApp address. The address is derived from the adapter's OApp ID: the OApp admin party ID and the ID string from Step 4:

   ```text theme={null}
   appUID      = lowercase hex of keccak256(utf8("<OApp admin party ID>|<OApp ID string>"))
   oappAddress = keccak256(0x01 || utf8(appUID))
   ```

   Use the ID string of the OApp ID, which can differ from the token's instrument ID. Work with LayerZero Labs to confirm the address before you set it.
2. **Set the DVNs.** Configure the same DVN set on the EVM send and receive configuration as on the Canton side. See [DVN and Executor Configuration](https://docs.layerzero.network/v2/developers/evm/configuration/dvn-executor-config.md).
3. **Set the confirmations** for each direction to the values agreed in Step 1.
4. **Set enforced options** for sends to Canton.
5. **Match decimals.** Use the same `sharedDecimals` on the EVM OFT as in the adapter configuration.

## Step 8: Register Receivers

A LayerZero message names its receiver with 32 bytes. A Canton party ID is `hint::1220<64 hex characters>`. Canton calls everything after `::` the fingerprint: `1220` is a multihash header for SHA-256, followed by a 32-byte digest. LayerZero calls the 64 hex characters of that digest the fingerprint, and this page uses that meaning. The message carries only those 32 bytes, and the adapter's registry maps them back to the full party. Canton treats party IDs as opaque, so this mapping is a LayerZero convention. For Canton Coin, use the Value Transfer API or Stargate to derive it.

Before a party can receive tokens from another chain, it must register in the adapter's registry. The party exercises `SetPartyId` on the `Registry` with its hint, and pays the registration fee from its own holdings if the configuration sets one. The registry key is the fingerprint of the party that exercises `SetPartyId`, and the hint is a value that party supplies. A party with its own namespace, such as an external party created with its own key, is the only party that can register its fingerprint. Parties that share a namespace can each set or replace the entry for that shared fingerprint. For Canton Coin, use the Value Transfer API or Stargate to register: they derive the hint from the full party ID and refuse to re-point a namespace that another party holds. A wallet can ask its user to sign the registration during onboarding.

If a party is not registered, delivery to it waits. The tokens stay burned or locked on the source chain. The `lzReceive` request is accepted, but its settlement cannot complete. The LayerZero executor can retry the settlement after the party registers, and the delivery can then complete.

> [!WARNING]
>
> The registry key is the 32-byte fingerprint alone. All parties in one namespace, for example the local parties on one validator, share a fingerprint. If a second party in the namespace registers, it replaces the first, and every later inbound transfer for that fingerprint goes to the second party. Register only one receiving party per namespace.

## Send from Canton to the EVM Chain

1. **Get the fee.** The fee is quoted from VER off the ledger, through the read API of LayerZero's VER sequencer (see [VER](https://docs.layerzero.network/v2/developers/canton/protocol-overview.md#the-virtual-endpoint-rollup-ver)). Get an access token from LayerZero Labs.
2. **Submit.** The sender's wallet exercises `OApp_LzSend` on the adapter. The command includes:
   * the send parameters: destination EID, receiver (the 32-byte EVM address), amount, minimum amount, extra options, and an optional compose message
   * the sender's token holdings to spend
   * Amulet holdings and the fee amount for the protocol fee
   * the configuration, rate limiter, and request factory references
   * the disclosed LayerZero contracts from Step 2
3. **Settle.** The lock/unlock adapter moves the amount to the custody party, and the burn/mint adapter burns it. The send also creates a request. VER processes it, and the `lzowner` party accepts or rejects it. On accept, VER emits the packet and the DVNs verify it. The LayerZero executor settles an accepted send separately. For rejected sends and refunds, see [Step 5](https://docs.layerzero.network/v2/developers/canton/protocol-overview.md#step-5-the-layerzero-executor-settles-the-send).
4. **Receive on EVM.** The DVNs verify the packet, and the executor calls `lzReceive` on the EVM OFT, which credits the receiver as on any EVM pathway.

## Send from Another Chain to Canton

A send into Canton is different from a send between EVM chains. The source chain cannot check the receiver, so the receiving party must be ready on Canton before anyone sends.

* **The message carries only part of the receiver's address.** The `to` field holds the 32-byte fingerprint of the party ID. The adapter's registry on Canton maps it back to the full party ID (see [Step 8](#step-8-register-receivers)).
* **The receiver must register first, on Canton.** A party registers by signing `SetPartyId` with its own Canton wallet or key and paying the fee from its own holdings on Canton. No source-chain transaction can register it. Parties that share a namespace can each set the entry for that namespace (see [Step 8](#step-8-register-receivers)).
* **The receiver's participant node must run the LayerZero packages.** To register, the node that hosts the party must have uploaded and vetted the LayerZero packages. Many Canton wallets and custodians do not run them.

### Recommended: Build the Send with LayerZero Tooling

For Canton Coin, use [Stargate](https://docs.layerzero.network/v2/developers/canton/canton-coin/bridge-with-stargate.md) or the [Value Transfer API](https://docs.layerzero.network/v2/developers/canton/canton-coin/value-transfer-api.md). They take the full Canton party ID and convert it to the 32-byte receiver value. They refuse to build a transfer if the party is not registered or if its fingerprint is registered to a different party. The Value Transfer API also prepares the registration transaction for the receiving party, which signs it on Canton with its own wallet. Neither can register the party from the source chain.

For other tokens on Canton, work with the token issuer or LayerZero Labs before you build sends, and check every item in the [pre-send checklist](#pre-send-checklist).

### Build the Send Yourself

> [!WARNING]
>
> **If you build an OFT send into Canton yourself and the receiving party is not registered in the adapter's registry, your funds will be stuck.** This includes a receiving party whose hosting participant node has not uploaded and vetted the LayerZero DAR packages, because that party cannot register until its node runs them. The source chain burns or locks the tokens, but the delivery on Canton cannot complete. It stays pending until the receiving party registers.
>
> A call to `send()` on an OFT on an EVM chain, HyperEVM, or Solana does not check the Canton receiver. Stargate and the Value Transfer API do. **We strongly recommend that you do not build OFT sends into Canton yourself.** If funds are stuck, recovery needs action from the receiver's node operator, a move of the party to a different node, or intervention by LayerZero. It is not practical for an end user to do this alone. LayerZero does not guarantee recovery or a recovery time. To ask for help, [contact the LayerZero team](https://layerzeronetwork.typeform.com/to/U9hMgxf1).
>
> Three mistakes cannot be fixed by registering the receiver:
>
> * **A `to` value that is not a party fingerprint,** for example a hashed party ID, an EVM address, or a Solana address. No party can register that value, so the delivery never completes.
> * **A fingerprint that is registered to a different party,** for example another local party on the same validator. The tokens are delivered to that party, and only that party can send them back.
> * **A compose message on the send.** The Canton OApp refuses the delivery, whoever the receiver is.
>
> If you build sends yourself, you are responsible for every item in the [pre-send checklist](#pre-send-checklist).

1. **Encode the receiver.** Set `to` in the `SendParam` to the receiver party's fingerprint: the 64 hex characters after `1220` in its party ID, as 32 bytes. Do not hash the party ID. Do not use an EVM address, a Solana address, or the hint.
2. **Send.** Call `quoteSend` and `send` on the OFT, as on any pathway. See the [EVM OFT quickstart](https://docs.layerzero.network/v2/developers/evm/oft/quickstart.md). Leave `composeMsg` empty. A Canton OApp rejects any inbound message that carries a compose message, so the delivery never completes and the tokens stay burned or locked on the source chain. Registering the receiver does not fix this. Do not set a native drop. The fee is charged, but nothing is delivered on Canton.
3. **Automatic delivery.** After the DVNs verify the packet, the LayerZero executor delivers it into Canton. VER processes the request, and the executor settles it. The adapter's callback resolves the receiver through the registry. The receiver then gets a CIP-0056 transfer instruction from the custody party or the mint escrow party. The receiver may need to accept it in a separate transaction, depending on the token's transfer rules. The instruction expires after 24 hours. LayerZero does not resend an expired instruction automatically. To have the tokens delivered again, [contact the LayerZero team](https://layerzeronetwork.typeform.com/to/U9hMgxf1).
4. **Rate limits.** If an inbound rate limit is reached, the `lzReceive` request is still accepted, and the settlement waits. The LayerZero executor retries the settlement after the limit's capacity recovers.

### If the Receiver Is Not Ready

In every case below, the tokens are already burned or locked on the source chain. The sender cannot cancel or reverse the transfer from the source chain.

| Problem | What happens on Canton | How it is resolved | Who must act |
| - | - | - | - |
| The party is not registered | The delivery cannot complete. The funds are stuck in a pending delivery. | The party registers. The pending delivery can then complete. LayerZero does not guarantee a time. If the tokens do not arrive, [contact the LayerZero team](https://layerzeronetwork.typeform.com/to/U9hMgxf1). | The receiver |
| The party's node has not vetted the LayerZero packages | The party cannot register, so the funds are stuck as above | The node operator vets the packages, the party moves to a node that has them, or the receiver runs their own node. Then the party registers. | The node operator and the receiver |
| The fingerprint is registered to a different party | The delivery succeeds, to that other party. Local parties on one validator share a fingerprint by default. | Only the party that received the tokens can send them back | The other party |
| `to` is not a party fingerprint, for example a hashed party ID or an EVM address | The delivery cannot complete, and no party can ever register that value. The funds are stuck. | No protocol path. Only LayerZero can intervene. [Contact the LayerZero team](https://layerzeronetwork.typeform.com/to/U9hMgxf1) with the source transaction hash. | LayerZero |
| The transfer instruction is not accepted within 24 hours | The instruction expires. The tokens return to the custody or mint escrow party. | The token's operator delivers the tokens again on request | The token's operator (LayerZero for Canton Coin) |
| `composeMsg` is set | The delivery is refused on every attempt. The funds are stuck. | No protocol path. [Contact the LayerZero team](https://layerzeronetwork.typeform.com/to/U9hMgxf1) with the source transaction hash. | The token's operator (LayerZero for Canton Coin) |
| The amount is above the adapter's per-message cap | The delivery is refused on every attempt. The funds are stuck. | No protocol path. [Contact the LayerZero team](https://layerzeronetwork.typeform.com/to/U9hMgxf1) with the source transaction hash. | LayerZero |

The adapter stores the amount in local decimals as a 64-bit integer, so the per-message cap is (2^63 − 1) / 10^`localDecimals` tokens. This is not a Canton or holding limit. For Canton Coin, the cap is about 922 million CC per message.

### Pre-Send Checklist

Check every item before the first send to a Canton party, and again if the party or its node changes.

1. **The receiving party exists and is funded.** It holds Canton Coin on Canton for the registration fee, and its own Canton wallet or key can sign the registration.
2. **Its node runs the LayerZero packages.** Every node that hosts the party has vetted the [LayerZero packages](https://docs.layerzero.network/v2/developers/canton/technical-overview.md#layerzero-packages). The node operator vets each new LayerZero package version.
3. **The party is registered for this token.** For Canton Coin, `POST /v1/register-canton-party` on the Value Transfer API without `holdings` returns `{"status": "registered", "partyId": "<partyId>"}`.
4. **The fingerprint is not taken by another party.** If the fingerprint is registered to a different party, the same call returns HTTP 409 (`…its namespace is already registered to a different party`). Do not send: the tokens would go to that party.
5. **The receiver value is the fingerprint.** `to` is the 64 hex characters after `1220` in that party ID, as 32 bytes.
6. **The party can accept the transfer.** For Canton Coin, the party has a transfer preapproval (One-step Transfers in Loop), or someone accepts the transfer instruction within 24 hours.
7. **No compose message and no native drop** are set on the send. A compose message makes the delivery fail (see [If the Receiver Is Not Ready](#if-the-receiver-is-not-ready)).
8. **Send a small test amount first,** and confirm that it arrives on Canton before you send more.

## Verify the Transfer

* On Canton, look up the transaction or the receiver's holdings in [Lighthouse](https://lighthouse.cantonloop.com), or read the holdings from the receiver's participant node.
* On the EVM chain, check the transaction in the chain's block explorer.
* Trace a message end to end by its GUID or source transaction hash with the [LayerZero Scan API](https://docs.layerzero.network/v2/tools/layerzeroscan/api.md). For a send from Canton, Scan indexes the transaction in which `lzowner` commits the VER result, not the update ID that your wallet returns.

## Next Steps

* [Protocol Overview](https://docs.layerzero.network/v2/developers/canton/protocol-overview.md): how VER processes requests
* [Technical Overview](https://docs.layerzero.network/v2/developers/canton/technical-overview.md): the Canton model behind each step
* [EVM OFT quickstart](https://docs.layerzero.network/v2/developers/evm/oft/quickstart.md): the EVM side in detail
