Skip to content

Commit d4a38cf

Browse files
authored
fix(Scroll): Approve on select ERC20 withdrawals (#575)
ERC20s with custom L2 gateways on Scroll require token approvals in order to initiate a withdrawal.
1 parent 2304cdc commit d4a38cf

File tree

4 files changed

+254
-57
lines changed

4 files changed

+254
-57
lines changed

contracts/Scroll_SpokePool.sol

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,26 @@ import "./SpokePool.sol";
55
import "@scroll-tech/contracts/L2/gateways/IL2GatewayRouter.sol";
66
import "@scroll-tech/contracts/libraries/IScrollMessenger.sol";
77

8+
interface IL2GatewayRouterExtended is IL2GatewayRouter {
9+
function defaultERC20Gateway() external view returns (address);
10+
11+
function getERC20Gateway(address) external view returns (address);
12+
}
13+
814
/**
915
* @title Scroll_SpokePool
1016
* @notice Modified SpokePool contract deployed on Scroll to facilitate token transfers
1117
* from Scroll to the HubPool
1218
* @custom:security-contact [email protected]
1319
*/
1420
contract Scroll_SpokePool is SpokePool {
21+
using SafeERC20Upgradeable for IERC20Upgradeable;
22+
1523
/**
1624
* @notice The address of the official l2GatewayRouter contract for Scroll for bridging tokens from L2 -> L1
1725
* @dev We can find these (main/test)net deployments here: https://docs.scroll.io/en/developers/scroll-contracts/#scroll-contracts
1826
*/
19-
IL2GatewayRouter public l2GatewayRouter;
27+
IL2GatewayRouterExtended public l2GatewayRouter;
2028

2129
/**
2230
* @notice The address of the official messenger contract for Scroll from L2 -> L1
@@ -51,7 +59,7 @@ contract Scroll_SpokePool is SpokePool {
5159
* @param _hubPool Hub pool address to set. Can be changed by admin.
5260
*/
5361
function initialize(
54-
IL2GatewayRouter _l2GatewayRouter,
62+
IL2GatewayRouterExtended _l2GatewayRouter,
5563
IScrollMessenger _l2ScrollMessenger,
5664
uint32 _initialDepositId,
5765
address _crossDomainAdmin,
@@ -66,7 +74,7 @@ contract Scroll_SpokePool is SpokePool {
6674
* @notice Change the L2 Gateway Router. Changed only by admin.
6775
* @param _l2GatewayRouter New address of L2 gateway router.
6876
*/
69-
function setL2GatewayRouter(IL2GatewayRouter _l2GatewayRouter) public onlyAdmin nonReentrant {
77+
function setL2GatewayRouter(IL2GatewayRouterExtended _l2GatewayRouter) public onlyAdmin nonReentrant {
7078
_setL2GatewayRouter(_l2GatewayRouter);
7179
}
7280

@@ -88,9 +96,14 @@ contract Scroll_SpokePool is SpokePool {
8896
* @param l2TokenAddress Address of the token to bridge.
8997
*/
9098
function _bridgeTokensToHubPool(uint256 amountToReturn, address l2TokenAddress) internal virtual override {
91-
// The scroll bridge handles arbitrary ERC20 tokens and is mindful of
92-
// the official WETH address on-chain. We don't need to do anything specific
93-
// to differentiate between WETH and a separate ERC20.
99+
// Tokens with a custom ERC20 gateway require an approval in order to withdraw.
100+
address erc20Gateway = l2GatewayRouter.getERC20Gateway(l2TokenAddress);
101+
if (erc20Gateway != l2GatewayRouter.defaultERC20Gateway()) {
102+
IERC20Upgradeable(l2TokenAddress).safeIncreaseAllowance(erc20Gateway, amountToReturn);
103+
}
104+
105+
// The scroll bridge handles arbitrary ERC20 tokens and is mindful of the official WETH address on-chain.
106+
// We don't need to do anything specific to differentiate between WETH and a separate ERC20.
94107
// Note: This happens due to the L2GatewayRouter.getERC20Gateway() call
95108
l2GatewayRouter.withdrawERC20(
96109
l2TokenAddress,
@@ -116,7 +129,7 @@ contract Scroll_SpokePool is SpokePool {
116129
require(_xDomainSender == crossDomainAdmin, "Sender must be admin");
117130
}
118131

119-
function _setL2GatewayRouter(IL2GatewayRouter _l2GatewayRouter) internal {
132+
function _setL2GatewayRouter(IL2GatewayRouterExtended _l2GatewayRouter) internal {
120133
address oldL2GatewayRouter = address(l2GatewayRouter);
121134
l2GatewayRouter = _l2GatewayRouter;
122135
emit SetL2GatewayRouter(address(_l2GatewayRouter), oldL2GatewayRouter);

deployments/scroll/Scroll_SpokePool.json

Lines changed: 51 additions & 50 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)