Homepage | Docs | Developers
Quickstart | Configuration | Message Execution Options | Composer Overview
A set of Composer examples to integrate LayerZero composer contracts with the Omnichain Fungible Token (OFT) standard.
- Prerequisite Knowledge
- Introduction
- Requirements
- Scaffold this Example
- Helper Resources
- Helper Tasks
- Setup
- Build
- Deploy
- Enable Messaging (for manually deployed OFTs only)
- Stargate to Aave Supply Task
- Appendix
Before diving into this repository you should understand:
- OFT Standard — how omnichain ERC20s are minted/burned across chains.
- Composer Pattern — how OFT transfers can be extended with compose payloads.
- Aave v3 lending flow.
The OFT Composer library demonstrates how to run post-bridge workflows on the destination chain. Ready-to-run contract live in contracts/ and it's deployment script live in deploy/:
AaveV3Composerroutes bridged tokens through Stargate and supplies them to an Aave v3 pool.
Learn more about OFT (Omnichain Fungible Token)
- git
- Node.js ≥ 18.18
- pnpm ≥ 8.15 (enable via
corepack enable)
git clone https://github.com/lzJxhn/ethglobal-ba-2025
cd ethglobal-ba-2025Run pnpm hardhat to list every built-in task. The most relevant tasks for this example are:
lz:deploy— deploy and tag composer contracts per network.lz:oapp:config:init/lz:oapp:wire— bootstrap and apply messaging configs.lz:oft:send— send OFT tokens without composer logic (useful for smoke tests).aave:supply— bridge tokens through Stargate and compose intoAaveV3Composer.
Copy the template and fill in every value before running builds, deploys, or tasks:
cp .env.example .envPRIVATE_KEY="0xyourdeployer"AAVE_V3_POOL_ADDRESS/STARGATE_POOL_ADDRESSare required bydeploy/AaveV3Composer.ts.
Edit hardhat.config.ts and align networks with the Endpoint IDs you intend to use. Example configuration:
...
networks: {
'arbitrum-mainnet': {
eid: EndpointId.ARBITRUM_V2_MAINNET,
url: process.env.RPC_URL_ARB || 'https://arbitrum.gateway.tenderly.co',
accounts,
},
'base-mainnet': {
eid: EndpointId.BASE_V2_MAINNET,
url: process.env.RPC_URL_BASE || 'https://base.gateway.tenderly.co',
accounts,
},
...Ensure every network listed here has a matching RPC_URL_* entry in .env.
Note: you don't have to use mainnet as in the demo, you can also use testnets, just make sure to use testnets where stargate and aave contracts are deployed. See Resources.
Install dependencies and compile contracts:
pnpm install
pnpm compile # runs both Hardhat + Forge toolchainsNeed a specific tool only? Run pnpm compile:hardhat or pnpm compile:forge.
Run unit tests with pnpm test, or select suites via pnpm test:hardhat / pnpm test:forge.
- Script:
examples/oft-composers/deploy/AaveV3Composer.ts - Required
.envkeys:PRIVATE_KEY,AAVE_V3_POOL_ADDRESS,STARGATE_POOL_ADDRESS, relevantRPC_URL_*. - Constructor:
(aavePool, stargatePool).
AAVE_V3_POOL_ADDRESS="0xDstAavePool" \
STARGATE_POOL_ADDRESS="0xDstStargateContract" \
pnpm hardhat lz:deploy --tags AaveV3ComposerThe script asserts both addresses exist and belong to deployed contracts before broadcasting. Double-check that the Stargate pool you specify supports the token you’ll bridge (e.g., USDC on Arbitrum Sepolia) and that the Aave pool lives on the hub chain that will execute the supply.
If you manually deployed OFTs (Asset/Share, adapters, or any custom OApp), you still need to wire them with LayerZero. There are two ways to do it—pick the one that matches your tooling:
-
This example already ships a
layerzero.config.tsthat targets LayerZero’s default DVNs/Executors. Update the contract names/EIDs if you changed them during deployment. -
Run wiring directly:
pnpm hardhat lz:oapp:wire --oapp-config layerzero.custom.config.ts
This is the quickest path and mirrors the standard OFT example in EX_README.md.
-
Generate per-mesh config scaffolding:
npx hardhat lz:oapp:config:init --contract-name MyOFT --oapp-config layerzero.custom.config.ts
-
Fill in DVNs, executors, and enforced gas options using the
TwoWayConfighelpers. -
Wire each config once all contracts exist:
pnpm hardhat lz:oapp:wire --oapp-config layerzero.custom.config.ts
Skip this entire section if you are using the Aave/Stargate composer workflow described below—Stargate pools already implement OFT semantics, so no extra wiring is required beyond configuring Stargate itself.
File: examples/oft-composers/tasks/supplyAave.ts
-
Run the task with CLI parameters (replace placeholders with live addresses/amounts):
pnpm hardhat aave:supply \ --src-oft <0xSrcStargateContract> \ --dst-eid <DstEID> \ --composer <0xComposerAddress> \ --amount-ld <AmountInLocalDecimals> \ --network <NetworkInHardhatConfig>
amount-ldis specified in local decimals (1,000,000 = 1 USDC if the pool uses 6 decimals).compose-gas-limitdefaults to395000.
-
The task automatically:
- Encodes the compose payload (receiver address).
- Quotes Stargate fees and approves ERC20 transfers when needed.
- Sends the transaction with the correct messaging fee (native or LZ token).
Monitor progress on LayerZero Scan.
pnpm test
pnpm test:forge # only Forge- Append new networks to
hardhat.config.tsand.env. - Add composer and OFT addresses for the new chain to your deployment config.
- Extend
layerzero.*.config.tspathways so the new chain can talk to existing hubs/spokes. - Re-run
lz:oapp:wirewith the updated config file.
Need help? Reach out in the LayerZero Discord or check the Developer Docs.