Skip to main content

Why Alt variants on Tempo

Tempo has no native gas token. Sending msg.value > 0 reverts, which means the standard fee payment path (fees via msg.value to the endpoint) does not work. Tempo uses EndpointV2Alt instead of the standard EndpointV2. EndpointV2Alt replaces native token fee payment with ERC-20 token transfers using LZEndpointDollar (LZD). OFTAlt and OAppAlt are the contract variants designed to work with this ERC-20 fee path.
Building an OApp? OAppAlt changes only the fee payment path: _payNative transfers LZD to the endpoint instead of using msg.value. The receive side is identical to OAppReceiver. Everything else (messaging, peer configuration, security) works the same way. Import from @layerzerolabs/oapp-alt-evm/contracts/oapp/OAppAlt.sol.

How standard OFT fee payment works

On a typical EVM chain, OFT pays LayerZero messaging fees by attaching native value:
// Standard OFT on Ethereum, Arbitrum, etc.
MessagingFee memory fee = oft.quoteSend(sendParam, false);
oft.send{value: fee.nativeFee}(sendParam, fee, refundAddress);
The endpoint’s _payNative function reads msg.value and forwards native tokens to the message library. The endpoint refunds excess native value to the sender.

EndpointV2Alt and the ERC-20 fee path

On Tempo, EndpointV2Alt overrides _payNative to delegate to _payToken, which:
  1. Rejects native value: reverts with LZ_OnlyAltToken if msg.value > 0
  2. Reads ERC-20 balance: _suppliedNative() returns IERC20(nativeErc20).balanceOf(address(this)) instead of msg.value
  3. Exposes the fee token: nativeToken() returns the LZD address instead of address(0)
OFTAlt contracts use this ERC-20 fee path. Before calling send(), the caller must approve and transfer LZD to the endpoint.

Comparison table

AspectOFTOFTAltOFTAdapterOFTAdapterAlt
Fee paymentmsg.value (native)ERC-20 transferFrom (LZD)msg.value (native)ERC-20 transferFrom (LZD)
EndpointEndpointV2EndpointV2AltEndpointV2EndpointV2Alt
msg.valuerequired for feesmust be 0required for feesmust be 0
Native dropsupportednot supportedsupportednot supported
Token modelnew omnichain tokennew omnichain tokenwraps existing tokenwraps existing token
Import path@layerzerolabs/oft-evm/contracts/OFT.sol@layerzerolabs/oft-alt-evm/contracts/OFTAlt.sol@layerzerolabs/oft-evm/contracts/OFTAdapter.sol@layerzerolabs/oft-alt-evm/contracts/OFTAdapterAlt.sol

Contract interface

OFTAlt extends the standard OFT interface but targets EndpointV2Alt:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;

import { OFTAlt } from "@layerzerolabs/oft-alt-evm/contracts/OFTAlt.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

contract MyOFTAlt is OFTAlt {
    constructor(
        string memory _name,
        string memory _symbol,
        address _lzEndpoint, // EndpointV2Alt address on Tempo
        address _delegate
    ) OFTAlt(_name, _symbol, _lzEndpoint, _delegate) Ownable(_delegate) {}
}
For adapting an existing token on Tempo, use OFTAdapterAlt:
import { OFTAdapterAlt } from "@layerzerolabs/oft-alt-evm/contracts/OFTAdapterAlt.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

contract MyOFTAdapterAlt is OFTAdapterAlt {
    constructor(
        address _token,        // existing ERC-20 or TIP-20 on Tempo
        address _lzEndpoint,   // EndpointV2Alt address
        address _delegate
    ) OFTAdapterAlt(_token, _lzEndpoint, _delegate) Ownable(_delegate) {}
}
For TIP-20 tokens that require mint/burn on Tempo, use TIP20MintBurnOFTAltAdapter. The adapter must hold the ISSUER_ROLE to mint and burn.

Fee payment differences

Standard OFT (other chains)

// Fees paid via msg.value
MessagingFee memory fee = oft.quoteSend(sendParam, false);
oft.send{value: fee.nativeFee}(sendParam, fee, refundAddress);

OFTAlt (Tempo)

// Fees paid via ERC-20 transfer
MessagingFee memory fee = oft.quoteSend(sendParam, false);

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

// Send with msg.value = 0
oft.send{value: 0}(sendParam, fee, refundAddress);
On Tempo, you must wrap a whitelisted stablecoin into LZD and approve the OFT before calling send(). See the LZD reference for the wrap flow.

TempoOFTWrapper

The TempoOFTWrapper simplifies the fee payment flow by bundling wrap, approve, and send into a single call. Instead of managing 5 transactions, you approve once and call sendOFT:
function sendOFT(
    address _oft,
    address _feeToken,
    SendParam calldata _sendParam,
    uint256 _maxNativeFee
) public returns (MessagingReceipt memory, OFTReceipt memory)

Parameters

NameTypeDescription
_oftaddressOFT contract to send through
_feeTokenaddresswhitelisted 6-decimal stablecoin to pay fees with. Cannot be LZD itself
_sendParamSendParamstandard OFT send parameters
_maxNativeFeeuint256maximum LZD fee. Reverts if quoted fee exceeds this
If oft.token() == _feeToken, the wrapper pulls amountLD + nativeFee in a single transfer. Otherwise, it pulls asset and fee tokens separately. See the how-to guide for a complete walkthrough.
ContractAddress
TempoOFTWrapper0xbb95daf376cd63f258d7c37a4efe57c10055e8e0

Interoperability

OFTAlt on Tempo communicates with standard OFT deployments on other chains without issue. The LayerZero protocol handles translation between fee models:
  • Sending from Tempo: the sender pays fees in LZD via OFTAlt. The destination chain receives the message as usual.
  • Receiving on Tempo: the sender on the source chain pays fees in the source chain’s native token using standard OFT. The Tempo-side OFTAlt receives the message without requiring LZD from the receiver.
No changes are needed to existing OFT contracts on other chains. The cross-chain message format is the same.

Choosing the right contract

ScenarioTempo contractOther chains
New ERC-20, minted on TempoOFTAltOFT
Existing ERC-20 on Tempo, lock/unlock bridgingOFTAdapterAltOFT or OFTAdapter
Existing TIP-20 on Tempo, mint/burn bridgingTIP20MintBurnOFTAltAdapterOFT or OFTAdapter
OFTAlt is for new omnichain tokens where Tempo is a mint chain. It deploys a fresh ERC-20 on Tempo and handles cross-chain mint/burn. OFTAdapterAlt wraps an existing ERC-20 that already lives on Tempo. It locks tokens in the adapter on send and unlocks on receive. This is the Alt equivalent of OFTAdapter, targeting EndpointV2Alt instead of EndpointV2. TIP20MintBurnOFTAltAdapter wraps a TIP-20 token using mint/burn instead of lock/unlock. The adapter must hold ISSUER_ROLE on the TIP-20 token. TIP-20 tokens use mint/burn because the ISSUER_ROLE model is designed around controlled supply, and lock/unlock would concentrate tokens in the adapter contract instead of adjusting supply directly. On other chains, keep using standard OFT or OFTAdapter. No changes needed. The Tempo-side adapter connects to EndpointV2Alt while the other chains continue using EndpointV2. LayerZero routes messages between them without extra configuration.