Skip to main content

Design Philosophy

Security modules (fee, rate limiting, pause-by-destination) are independent, upgradeable layers that compose through inheritance without modifying core OFT logic. Allowlist controls live on the token (ERC20Plus), not in the extension stack. Token logic (ERC20Plus) is fully decoupled from cross-chain OFT logic (OFT variants). The token can exist without an OFT, and the OFT works with any ERC20 that implements IERC20Metadata and the necessary mint/burn functions with appropriate role-based access control. All storage uses EIP-7201 namespaced storage slots, preventing storage collisions across inheritance chains and making proxy upgrades safe by construction.

Four-Layer Architecture

+----------------------------------------------------------+  IOFTExtended
|  Cross-Chain Extensions                                  |
|  Fee | RateLimiter | PauseByID                           |
|  (composable, per-destination configuration)             |
+----------------------------------------------------------+  IOFT
|  Cross-Chain Transport                                   |
|  BurnMint | LockUnlock | Native | BurnSelfMint           |
|  (send/receive via LayerZero V2)                         |
+==========================================================+  IERC20Plus
|  Token Controls                                          |
|  Allowlist | Pause | Fund Recovery                       |
|  (apply to all token operations, not just cross-chain)   |
+----------------------------------------------------------+  IERC20
|  Token Core                                              |
|  ERC20 + ERC20Permit (transfer, approve, permit)         |
|  (OpenZeppelin ERC20Upgradeable)                         |
+----------------------------------------------------------+
The system is two independent deployment units — a Token Stack and an OFT Stack — connected by the IERC20Plus interface. Token Core (Layer 1): Standard ERC20 functionality built on OpenZeppelin’s ERC20Upgradeable and ERC20PermitUpgradeable. Transfers, approvals, balances, and gasless permit signatures. Token Controls (Layer 2): Allowlist (three-mode address restrictions), global pause, fund recovery, and role-based mint/burn access control. These apply to all token operations — a paused token blocks local transfers as well as cross-chain sends. Deployed as the ERC20Plus contract independently of any OFT. Cross-Chain Transport (Layer 3): Manages cross-chain send/receive. Each OFT variant implements a different transfer model (burn/mint, burn-self/mint, lock/unlock, native). Cross-Chain Extensions (Layer 4): Per-destination fee collection, rate limiting, and pause-by-destination controls. These modules intercept _debit and _credit to enforce policies before the underlying transfer executes.

Inheritance Hierarchy

Each green box is a deployable contract. Everything above is abstract. The Alt variants (OFTBurnMintAlt, OFTLockUnlockAlt, OFTBurnSelfMintAlt) follow the same hierarchy but target EndpointV2Alt for chains where ERC20 tokens are used for gas fees.

ERC20Plus Inheritance

Cross-Chain Message Flow

Send Path (Source Chain)

send()
  |
  v
OFTCoreBaseUpgradeable.send()
  |
  v
_debit() [overridden per variant]
  |-- whenNotPaused(_dstEid)              <-- PauseByID
  |-- _debitView()                        <-- Fee calculation
  |     |-- getFee(_dstEid, _amountLD)
  |     |-- _removeDust()
  |     +-- SlippageExceeded check
  |-- _outflow(_dstEid, _from, amount)    <-- Rate limit
  |     |-- Address exemption check
  |     +-- Token bucket decay
  +-- Transfer/burn + collect fee         <-- Allowlist & global pause
  |
  v
_buildMsgAndOptions()
  |
  v
_lzSend() --> LayerZero Endpoint
  |
  v
emit OFTSent(guid, dstEid, from, amountSentLD, amountReceivedLD)

Receive Path (Destination Chain)

LayerZero Endpoint delivers message
  |
  v
_lzReceive()
  |
  v
_credit() [overridden per variant]
  |-- _inflow(_srcEid, _to, _amountLD)   <-- Rate limit (inbound)
  +-- Mint/unlock/transfer to recipient  <-- No allowlist & pause checks (credit must not fail)
  |
  v
If compose message exists:
  +-- endpoint.sendCompose() --> downstream contract
  |
  v
emit OFTReceived(guid, srcEid, to, amountReceivedLD)

Transfer Model Mechanics

Burn/Mint

Source Chain                          Destination Chain
+--------------------+                +--------------------+
|  ERC20Plus         |                |  ERC20Plus         |
|                    |                |                    |
|  burn()            |  LayerZero V2  |  mint()            |
|                    |  ----------->  |                    |
|                    |                |                    |
|  OFTBurnMint       |                |  OFTBurnMint       |
+--------------------+                +--------------------+
The OFT must hold MINTER_ROLE and BURNER_ROLE on the ERC20Plus token. Total supply across all chains remains constant.

Burn-Self/Mint

Source Chain                          Destination Chain
+--------------------+                +--------------------+
|  ERC20Plus         |                |  ERC20Plus         |
|                    |                |                    |
|  transferFrom()    |  LayerZero V2  |  mint()            |
|  burn()            |  ----------->  |                    |
|                    |                |                    |
|  OFTBurnSelfMint   |                |  OFTBurnSelfMint   |
+--------------------+                +--------------------+
First transfers tokens from user to OFT via ERC20 allowance, then burns using burn(uint256) selector. The OFT must hold MINTER_ROLE on the destination token.

Lock/Unlock

Source Chain                          Destination Chain
+--------------------+                +--------------------+
|  ERC20Plus         |                |  ERC20Plus         |
|                    |                |                    |
|  transferFrom()    |  LayerZero V2  |  transfer()        |
|  (lock in OFT)     |  ----------->  |                    |
|                    |                |                    |
|  OFTLockUnlock     |                |  OFTLockUnlock     |
+--------------------+                +--------------------+
Tokens are locked in the OFT contract on the source chain and unlocked from the OFT contract on the destination. Only one lock/unlock OFT should exist per mesh to prevent supply fragmentation.

Native

Source Chain                          Destination Chain
+--------------------+                +--------------------+
|                    |                |                    |
|  msg.value         |  LayerZero V2  |  .call{value}      |
|  (ETH sent         |  ----------->  |  (ETH sent to      |
|   with tx)         |                |   recipient)       |
|                    |                |                    |
|  OFTNative         |                |  OFTNative         |
+--------------------+                +--------------------+
The OFT wraps/unwraps native tokens. msg.value must include both the transfer amount and the LayerZero messaging fee.

Upgradeability Model

All contracts support Transparent Upgradeable Proxy (TUP) and Beacon proxy patterns:
  • Proxy contract holds state (storage) and delegates calls to the implementation
  • Implementation contract holds logic and is stateless
  • EIP-7201 namespaced storage ensures each module’s storage is isolated at a deterministic slot, preventing collisions

Next Steps

  • ERC20Plus for the token core (layer 1)
  • OFTs for the cross-chain transport (layer 3)
  • Extensions for token controls and cross-chain extensions (layers 2 and 4)