From b1c835d4b31e414131965b488d312a608ef91053 Mon Sep 17 00:00:00 2001 From: Paul <108695806+pxrl@users.noreply.github.com> Date: Tue, 2 Sep 2025 00:19:19 +0000 Subject: [PATCH] improve(ZkSync_SpokePool): Read l2Bridge dynamically zkSync ERC20s are typically explicit about the L2 bridge to use, but Lens ERC20s are not. Lens WETH does supplies a valid l2Bridge address that can be used to withdraw from the chain. --- contracts/ZkSync_SpokePool.sol | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/contracts/ZkSync_SpokePool.sol b/contracts/ZkSync_SpokePool.sol index 83c51a633..d3af6f369 100644 --- a/contracts/ZkSync_SpokePool.sol +++ b/contracts/ZkSync_SpokePool.sol @@ -8,11 +8,11 @@ import "./SpokePool.sol"; // https://github.com/matter-labs/era-contracts/blob/6391c0d7bf6184d7f6718060e3991ba6f0efe4a7/zksync/contracts/bridge/L2ERC20Bridge.sol#L104 interface ZkBridgeLike { - function withdraw( - address _l1Receiver, - address _l2Token, - uint256 _amount - ) external; + function withdraw(address _l1Receiver, address _l2Token, uint256 _amount) external; +} + +interface IZkErc20 { + function l2Bridge() external view returns (address); } interface IL2ETH { @@ -166,7 +166,13 @@ contract ZkSync_SpokePool is SpokePool, CircleCCTPAdapter { zkUSDCBridge.withdraw(withdrawalRecipient, l2TokenAddress, amountToReturn); } } else { - zkErc20Bridge.withdraw(withdrawalRecipient, l2TokenAddress, amountToReturn); + // Elastic chain bridged tokens advertise custom bridge interface via the l2Bridge() getter. + address l2Bridge = IZkErc20(l2TokenAddress).l2Bridge(); + if (l2Bridge != address(0)) { + ZkBridgeLike(l2Bridge).withdraw(withdrawalRecipient, l2TokenAddress, amountToReturn); + } else { + zkErc20Bridge.withdraw(withdrawalRecipient, l2TokenAddress, amountToReturn); + } } }