feat: add WBTC OFT adapter#205
Draft
wesraph wants to merge 5 commits into
Draft
Conversation
Aave V3 governance froze the WETH reserve on Base around block 44890000. The unit tests touch Aave V3 borrow/repay paths through LiquidityPoolAave and LiquidityPoolAaveLongTerm, which all revert with `ReserveFrozen()` when forking from current head. Pinning the default Base fork to block 44880000 (the last block before the freeze) restores 29 previously-failing tests without changing any production code. Verified locally that all unit, fork, script, and coverage suites pass at the pinned block.
Each chain has its own block-number space, so applying a single FORK_BLOCK_NUMBER across every fork target breaks tests that fork from a different chain (e.g. test:ethereum at block 44.8M reverts because that block does not exist on Ethereum yet). Only honour the env var when neither DRY_RUN nor FORK_TEST is set — the same condition that picks the default Base fork URL.
There was a problem hiding this comment.
Pull request overview
Adds support for bridging WBTC via LayerZero OFT through the Repayer, following the existing USDT0 OFT adapter pattern (initiate-only flow).
Changes:
- Introduces
WBTCOFTAdapterand wires it intoRepayervia a new constructor arg (wbtcOft) andProvider.WBTC_OFTdispatch. - Extends config + scripts to carry
WBTCOFTaddresses (withZERO_ADDRESSfallback) and updates fork/unit tests accordingly. - Adds mock contracts + unit/fork tests for both “approval-required (adapter)” and “native burn” OFT behaviors.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
contracts/utils/WBTCOFTAdapter.sol |
New LayerZero OFT-based adapter implementing WBTC initiate flow (ETH approval vs non-ETH no-approval). |
contracts/Repayer.sol |
Adds WBTCOFTAdapter inheritance, constructor param, and Provider.WBTC_OFT dispatch in initiateRepay. |
contracts/interfaces/IRoute.sol |
Appends Provider.WBTC_OFT and centralizes InvalidToken() error on the interface. |
contracts/utils/USDT0Adapter.sol |
Removes redundant local InvalidToken() in favor of IRoute.InvalidToken(). |
contracts/testing/TestWBTCOFT.sol |
Adds WBTC/OFT mocks for both transferFrom (adapter) and burn (native) send modes. |
contracts/testing/TestRepayer.sol |
Extends test repayer constructor to pass through wbtcOft. |
test/Repayer.ts |
Updates deployments for new constructor arg and adds unit tests for WBTC OFT paths + revert cases. |
specific-fork-test/ethereum/RepayerWBTCOFT.ts |
New Ethereum fork test exercising real WBTC OFTAdapter behavior. |
specific-fork-test/ethereum/Repayer.ts |
Updates repayer deployment for new constructor arg. |
specific-fork-test/ethereum/RepayerUSDT0.ts |
Updates repayer deployment for new constructor arg. |
specific-fork-test/ethereum/RepayerGnosisOmnibridge.ts |
Updates repayer deployment for new constructor arg. |
specific-fork-test/gnosis/RepayerGnosisOmnibridge.ts |
Updates repayer deployment for new constructor arg. |
specific-fork-test/unichain/RepayerUSDT0.ts |
Updates repayer deployment for new constructor arg. |
specific-fork-test/polygon/RepayerUSDT0.ts |
Updates repayer deployment for new constructor arg. |
specific-fork-test/arbitrum/RepayerUSDT0.ts |
Updates repayer deployment for new constructor arg. |
scripts/deploy.ts |
Adds WBTCOFT fallback + appends new constructor arg in deployment. |
scripts/deployRepayer.ts |
Adds WBTCOFT fallback + appends new constructor arg in deployment. |
scripts/deployStandaloneRepayer.ts |
Adds WBTCOFT fallback + appends new constructor arg in deployment. |
scripts/upgradeRepayer.ts |
Adds WBTCOFT fallback + appends new constructor arg for upgrades. |
scripts/common.ts |
Adds numeric ProviderSolidity.WBTC_OFT = 10n and reverse mapping. |
network.config.ts |
Adds Provider.WBTC_OFT and WBTCOFT?: string across configs + populates addresses for supported chains. |
hardhat.config.ts |
Adjusts fork blockNumber usage so it only applies to the default Base fork (not FORK_TEST/DRY_RUN). |
.env.example |
Documents/pins FORK_BLOCK_NUMBER for Base fork stability. |
coverage-baseline.json |
Updates coverage baseline to reflect added coverage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mpetrunic
approved these changes
Apr 30, 2026
Member
|
maybe icebox for now since across uses different tokens |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
WBTCOFTAdapterto the Repayer, enabling WBTC bridging via LayerZero's OFT. Mirrors the existing USDT0 adapter (#183) — sameIOFTinterface, same Ethereum-vs-others approval branch, initiate-only (LayerZero auto-delivers).Closes #202.
What's added
Provider.WBTC_OFT(enum value10) appended toIRoute.solcontracts/utils/WBTCOFTAdapter.sol— new adapter; on Ethereum itforceApproves and the OFTAdapter pulls viatransferFrom, on every other chain the native OFT burns frommsg.senderdirectlycontracts/testing/TestWBTCOFT.sol—TestWBTC(8 decimals),TestWBTCOFTAdapter(transferFrom mode),TestWBTCOFTNative(burn mode)Repayer.solinheritsWBTCOFTAdapter, takes one new constructor arg (wbtcOft), dispatchesProvider.WBTC_OFTininitiateRepaydeploy.ts,deployRepayer.ts,deployStandaloneRepayer.ts,upgradeRepayer.ts) get aWBTCOFTfallback toZERO_ADDRESSand append the new constructor argnetwork.config.ts: newWBTC_OFTprovider,WBTCOFT?: stringfield on bothNetworkConfiginterfaces, populated for chains where the OFT is livetest/Repayer.ts(adapter approval mode, native burn mode, token mismatch, zero-address) + 1 fork test exercising the real Ethereum OFTAdapterRebalancer.solis untouched — like USDT0, WBTC OFT only flows through the Repayer.Verified deployment topology
All addresses confirmed on-chain via
cast(token(),decimals(),approvalRequired(),endpoint(),peers(...)).0x0555E30da8f98308EdB960aa94C0Db47230d2B9c0x2260…)0x0555E30da8f98308EdB960aa94C0Db47230d2B9c0x0555E30da8f98308EdB960aa94C0Db47230d2B9c0xC3f854B2970f8727D28527ECE33176faC67FeF480x0555E30da8f98308EdB960aa94C0Db47230d2B9c0x0555E30da8f98308EdB960aa94C0Db47230d2B9cTokens.WBTCentry in repo)All native OFTs inherit
OFTFeewithdefaultFeeBps = 0.minAmountLD == amountLDis intentional (no slippage); a future BitGo fee activation would revert there — that's an escalation problem, not an adapter problem.Out of scope (deferred, mirrors how USDT0 and CCTP V2 rolled out)
Provider.WBTC_OFTentries are added to anyPoolsroute list in this PR. That lands in a follow-up staging-deploy PR (same pattern as #197 for USDT0 and #201 for CCTP V2).Tokens.WBTCentries on Base/Avalanche/Unichain: don't exist yet. Required by the route-enablement PR (the adapter's runtime checkoft.token() == address(token)needsTokens.WBTCto point at the canonical OFT).Tokens.WBTCmismatch: BSC currently registers BTCB (0x7130…, 18 dec), OP registers bridged WBTC (0x68f1…); neither matches the OFT's underlying token. The route-enablement PR will need to switch these or add a separate token alias before turning onProvider.WBTC_OFTon those chains.Verification
castagainst public mainnet RPCs.LayerZeroHelper.sol.branches92.65 → 92.73;WBTCOFTAdapter.solitself at 100%).specific-fork-test/{arbitrum,ethereum,gnosis,polygon,unichain}/Repayer*.ts) updated for the new constructor arg.LiquidityPoolAave*tests fail onmainand on this branch withReserveFrozen()against the Base Aave V3 USDC reserve (recent governance freeze) — pre-existing, not introduced here.References
0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599