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

# LZEndpointDollar (LZD)

> Reference for LZEndpointDollar, the canonical USD-denominated fee token used by LayerZero on Tempo.

## What is LZD

LZEndpointDollar (LZD) is the canonical USD-denominated fee token for LayerZero on Tempo. Because Tempo has no native gas token, `EndpointV2Alt` uses LZD as the ERC-20 token for all LayerZero messaging fees.

The endpoint could accept a single TIP-20 token directly, but that would force users to hold one specific stablecoin. LZD is an ERC-20 wrapper around multiple whitelisted 6-decimal stablecoins (pathUSD, USDC.e, or USDT0), so users can pay fees with whichever USD stablecoin they have. Users wrap a supported stablecoin into LZD, then approve the endpoint or OFT to spend it.

## Endpoint mode detection

On any EVM chain, you can check the endpoint type by calling `nativeToken()`. On Tempo, it returns the LZD address:

```solidity wrap theme={null}
address feeToken = ILayerZeroEndpointV2(endpoint).nativeToken();

if (feeToken == address(0)) {
    // Standard Endpoint: pay fees with native token (msg.value)
} else {
    // Endpoint Alt: pay fees with ERC20 at feeToken address
    // On Tempo, feeToken = LZD address
}
```

## Fee payment flow

Paying LayerZero fees on Tempo requires wrapping a whitelisted stablecoin into LZD before sending:

1. **Quote**: call `quoteSend(sendParam, _payInLzToken)` to receive both `nativeFee` and `lzTokenFee`. LayerZero lets you choose the fee token via `_payInLzToken`. At the time of writing, `_payInLzToken` is not enabled on Tempo, so set it to `false` and use `nativeFee` (LZD).
2. **Approve stablecoin**: approve the LZD contract to spend your stablecoin.
3. **Wrap**: call `LZD.wrap(feeToken, recipient, amount)` to convert your stablecoin into LZD.
4. **Approve LZD**: approve the OFT contract to spend your LZD.
5. **Send**: call `send()` with `msg.value = 0` and `MessagingFee(nativeFee, 0)`.

```solidity wrap theme={null}
// 1. Quote the fee
MessagingFee memory fee = oft.quoteSend(sendParam, false);

// 2. Approve stablecoin to LZD
IERC20(usdce).approve(address(lzd), fee.nativeFee);

// 3. Wrap USDC.e into LZD
lzd.wrap(usdce, msg.sender, fee.nativeFee);

// 4. Approve LZD to the OFT
IERC20(address(lzd)).approve(address(oft), fee.nativeFee);

// 5. Send with msg.value = 0
oft.send{value: 0}(sendParam, fee, refundAddress);
```

At the time of writing, `_payInLzToken` is not enabled on Tempo, so set it to `false`.

## API reference

### wrap

```solidity wrap theme={null}
function wrap(address _token, address _to, uint256 _amount) public nonReentrant onlyWhitelistedToken(_token)
```

Wraps a whitelisted stablecoin into LZD. Transfers the underlying token from `msg.sender` and mints LZD to `_to`.

#### Parameters

| Name     | Type    | Description                    |
| -------- | ------- | ------------------------------ |
| \_token  | address | whitelisted stablecoin to wrap |
| \_to     | address | address to receive minted LZD  |
| \_amount | uint256 | amount to wrap (6-decimal)     |

### unwrap

```solidity wrap theme={null}
function unwrap(address _token, address _to, uint256 _amount) public nonReentrant onlyWhitelistedToken(_token)
```

Unwraps LZD back into a whitelisted stablecoin. Burns LZD from `msg.sender` and transfers the underlying token to `_to`.

#### Parameters

| Name     | Type    | Description                          |
| -------- | ------- | ------------------------------------ |
| \_token  | address | whitelisted stablecoin to receive    |
| \_to     | address | address to receive underlying tokens |
| \_amount | uint256 | amount to unwrap (6-decimal)         |

### whitelistToken

```solidity wrap theme={null}
function whitelistToken(address _token) public onlyOwner
```

Adds a token to the whitelist. This is an owner-only admin function, so new fee tokens can only be added by the LZD contract owner. The token must have exactly 6 decimals and must not already be whitelisted.

#### Parameters

| Name    | Type    | Description          |
| ------- | ------- | -------------------- |
| \_token | address | token address to add |

### unwhitelistToken

```solidity wrap theme={null}
function unwhitelistToken(address _token) public onlyOwner
```

Removes a token from the whitelist.

#### Parameters

| Name    | Type    | Description             |
| ------- | ------- | ----------------------- |
| \_token | address | token address to remove |

### isWhitelistedToken

```solidity wrap theme={null}
function isWhitelistedToken(address _token) public view returns (bool isWhitelisted)
```

Returns whether a token is whitelisted.

#### Parameters

| Name    | Type    | Description    |
| ------- | ------- | -------------- |
| \_token | address | token to check |

### getWhitelistedTokens

```solidity wrap theme={null}
function getWhitelistedTokens() public view returns (address[] memory tokens)
```

Returns all whitelisted token addresses.

### getTokenBalance

```solidity wrap theme={null}
function getTokenBalance(address _token) public view returns (uint256 balance)
```

Returns the contract's balance of a specific underlying token.

#### Parameters

| Name    | Type    | Description    |
| ------- | ------- | -------------- |
| \_token | address | token to check |

### decimals

```solidity wrap theme={null}
function decimals() public view returns (uint8)
```

Returns `6`. LZD uses 6 decimals to match its underlying whitelisted stablecoins.

### Events

#### TokenWrapped

```solidity wrap theme={null}
event TokenWrapped(address indexed token, address indexed from, address indexed to, uint256 amount)
```

Emitted when a whitelisted token is wrapped into LZD.

#### TokenUnwrapped

```solidity wrap theme={null}
event TokenUnwrapped(address indexed token, address indexed from, address indexed to, uint256 amount)
```

Emitted when LZD is unwrapped back into a whitelisted token.

#### TokenWhitelisted

```solidity wrap theme={null}
event TokenWhitelisted(address indexed token, bool whitelisted)
```

Emitted when a token is added to or removed from the whitelist.

### Errors

| Error                                   | Cause                                        |
| --------------------------------------- | -------------------------------------------- |
| `NotWhitelisted(token)`                 | token is not on the whitelist                |
| `Whitelisted(token)`                    | token is already whitelisted (duplicate add) |
| `InvalidToken(token)`                   | token is zero address or the LZD contract    |
| `InvalidTokenDecimals(token, decimals)` | token does not have 6 decimals               |

## Quoting fees

`quoteSend()` returns a `MessagingFee` with both `nativeFee` and `lzTokenFee`. LayerZero lets applications choose the payment token via `_payInLzToken`. At the time of writing, `_payInLzToken` is not enabled on Tempo, so set it to `false` and read the fee from `nativeFee` (LZD):

```solidity wrap theme={null}
// false = quote in native fee token (LZD on Tempo)
MessagingFee memory fee = oft.quoteSend(sendParam, false);
// fee.nativeFee = amount of LZD required
// fee.lzTokenFee = 0 on Tempo while _payInLzToken is disabled
```

## msg.value behavior

Tempo's `EndpointV2Alt` rejects any transaction that sends native value:

* `msg.value > 0` reverts with `LZ_OnlyAltToken`
* There is no native drop. `addExecutorNativeDropOption` is not supported

<Warning>
  Always set `msg.value = 0` when calling `send()` on Tempo. Do not attach any native value to LayerZero transactions.
</Warning>

## Failure modes

| Revert reason                    | Cause                                              | Mitigation                                   |
| -------------------------------- | -------------------------------------------------- | -------------------------------------------- |
| `OFTAltCore__msg_value_not_zero` | `msg.value > 0` when calling `send()` on an OFTAlt | set `msg.value = 0`                          |
| `LZ_OnlyAltToken`                | `msg.value > 0` reaching the endpoint directly     | set `msg.value = 0`                          |
| `LZ_LzTokenUnavailable`          | `quoteSend(_, true)` called                        | use `quoteSend(_, false)`                    |
| `NotWhitelisted(token)`          | fee token not whitelisted by LZD                   | use pathUSD, USDC.e, or USDT0                |
| `InvalidTokenDecimals(token, d)` | token does not have 6 decimals                     | use a 6-decimal stablecoin                   |
| ERC-20 transfer failure          | insufficient LZD balance or missing approval       | wrap stablecoin into LZD and approve the OFT |

## Contract addresses

| Contract         | Address                                      |
| ---------------- | -------------------------------------------- |
| LZEndpointDollar | `0x0ceb237e109ee22374a567c6b09f373c73fa4cbb` |
