Stablecoin OFT provides multiple OFT variants to support different token economics and deployment scenarios. Each variant implements a different cross-chain transfer model. All share the same extension stack (fee, rate limiting, pause).
Decision Matrix
| Scenario | OFT | Why |
|---|
| Token with permissioned burn and mint | OFTBurnMint | Burn on source, mint on destination. No locked collateral. |
| Token with permissionless self-burn and permissioned mint | OFTBurnSelfMint | Transfers to OFT via allowance, then self-burns. Mint on destination. |
| Existing token with supply on one chain | OFTLockUnlock | Lock on source, unlock on destination. No supply change. |
| Native gas token (ETH, MATIC, etc.) | OFTNative | Wraps msg.value for cross-chain transfer. |
| Target chain uses ERC20 for gas fees | Alt variants | Same logic but built for EndpointV2Alt. |
OFTBurnMint
Burns tokens on the source chain and mints them on the destination chain. Supports any token that exposes mint and burn functions with (address, uint256) parameters. The OFT must be granted the required roles (e.g., MINTER_ROLE, BURNER_ROLE) to call these functions.
Key feature: Configurable function selectors allow the OFT to call non-standard mint/burn function names.
Constructor Parameters
| Parameter | Type | Description |
|---|
_token | address | Underlying ERC20 token address (must implement IERC20Metadata) |
_burnerMinter | address | Contract with burn/mint capabilities (can differ from _token) |
_endpoint | address | LayerZero EndpointV2 address |
_approvalRequired | bool | Whether the OFT needs ERC20 approval to burn |
_burnSelector | bytes4 | Function selector for burn, e.g., 0x9dc29fac for burn(address,uint256) |
_mintSelector | bytes4 | Function selector for mint, e.g., 0x40c10f19 for mint(address,uint256) |
_rateLimiterScaleDecimals | uint8 | Decimals to scale rate limit amounts (usually 0) |
Common Selector Values
| Function Signature | Selector |
|---|
mint(address,uint256) | 0x40c10f19 |
burn(address,uint256) | 0x9dc29fac |
issue(address,uint256) | 0x867904b4 |
redeem(address,uint256) | 0x1e9a6950 |
Initialization Parameters
| Parameter | Type | Description |
|---|
_initialAdmin | address | Address to be granted DEFAULT_ADMIN_ROLE and endpoint delegate |
_feeDeposit | address | Address that will receive any accrued fees |
function initialize(address _initialAdmin, address _feeDeposit) public initializer;
OFTBurnSelfMint
For tokens with a permissionless self-burn function (e.g., OpenZeppelin’s ERC20Burnable.burn(uint256)) and a permissioned mint function. On the send path, the OFT transfers tokens from the user to itself via ERC20 allowance, then calls the self-burn selector to destroy them. On the receive path, it mints via the mint selector like OFTBurnMint.
Constructor Parameters
| Parameter | Type | Description |
|---|
_token | address | Token address that is also the burner/minter |
_endpoint | address | LayerZero EndpointV2 address |
_burnSelector | bytes4 | Function selector for burn |
_mintSelector | bytes4 | Function selector for mint |
_rateLimiterScaleDecimals | uint8 | Decimals to scale rate limit amounts |
Common Selector Values for OFTBurnSelfMint
| Function Signature | Selector |
|---|
mint(address,uint256) | 0x40c10f19 |
burn(uint256) | 0x42966c68 |
issue(address,uint256) | 0x867904b4 |
redeem(uint256) | 0xdb006a75 |
OFTLockUnlock
Locks tokens in the OFT contract on the source chain and unlocks (transfers) them from the OFT on the destination chain. No minting or burning occurs.
Constructor Parameters
| Parameter | Type | Description |
|---|
_token | address | Underlying ERC20 token address (must implement IERC20Metadata) |
_endpoint | address | LayerZero EndpointV2 address |
_rateLimiterScaleDecimals | uint8 | Decimals to scale rate limit amounts |
approvalRequired is always true for lock/unlock since users must approve the OFT to transfer their tokens.
Only one lock/unlock OFT should exist per OFT mesh. If multiple lock/unlock OFTs exist on different chains, locked supply becomes fragmented and the system cannot guarantee solvency.
OFTNative
Wraps native tokens (ETH, MATIC, AVAX, etc.) for cross-chain transfer. Users send native tokens as msg.value along with the send() call.
Constructor Parameters
| Parameter | Type | Description |
|---|
_localDecimals | uint8 | Decimals of the native token (18 for ETH) |
_endpoint | address | LayerZero EndpointV2 address |
_rateLimiterScaleDecimals | uint8 | Decimals to scale rate limit amounts |
Send Behavior
The overridden send() function validates that msg.value equals exactly _fee.nativeFee + _sendParam.amountLD:
uint256 requiredMsgValue = _fee.nativeFee + _sendParam.amountLD;
if (msg.value != requiredMsgValue) {
revert IncorrectMessageValue(msg.value, requiredMsgValue);
}
Receive Behavior
Credits are sent as native token transfers using low-level .call{value}(). If the transfer fails (e.g., recipient is a contract without a receive function), the transaction reverts with CreditFailed(to, amountLD, revertData).
Properties
token() returns address(0) since there is no ERC20 token
approvalRequired() returns false since msg.value is used directly
- Dust removal is not applied to
amountLD since native token amounts always equal amountSentLD
Alt Variants
Some chains use an ERC20 token for gas fees instead of a native token. Because gas fees are paid in an ERC20, the sender must approve the endpoint to spend the fee token before sending a message. This changes the standard send() workflow: users need an additional ERC20 approval step for the fee token, and the endpoint pulls fees via transferFrom rather than accepting msg.value.
These chains use EndpointV2Alt instead of EndpointV2 to handle this difference. The Alt OFT variants are identical to their standard counterparts except they target EndpointV2Alt:
| Standard Variant | Alt Variant |
|---|
OFTBurnMint | OFTBurnMintAlt |
OFTBurnSelfMint | OFTBurnSelfMintAlt |
OFTLockUnlock | OFTLockUnlockAlt |
Alt variants inherit from the corresponding ExtendedRBACAltUpgradeable contracts. Constructor parameters and behavior are otherwise the same.
Multi-Chain Topology
Burn/Mint
+--------------+ +--------------+
| Chain A |<--->| Chain B |
| OFTBurnMint | | OFTBurnMint |
+------+-------+ +------+-------+
| |
+---------+----------+
|
+--------------+
| Chain C |
| OFTBurnMint |
+--------------+
All chains are equal peers. Each OFT burns on send and mints on receive. Total supply across all chains stays constant. Works the same way with OFTBurnSelfMint.
Lock/Unlock
+--------------+ +--------------+
| Chain B | | Chain C |
| OFTBurnMint | | OFTBurnMint |
+------+-------+ +------+-------+
| |
+----------+----------+
|
+----------------+
| Chain A |
| OFTLockUnlock |
+----------------+
One chain (the token’s home chain) deploys OFTLockUnlock, which locks tokens on send and unlocks on receive. All other chains deploy OFTBurnMint, which burns on send and mints on receive. This keeps a single pool of locked collateral on Chain A backing all circulating supply on remote chains.
Next Steps