@@ -5,18 +5,26 @@ import "./SpokePool.sol";
5
5
import "@scroll-tech/contracts/L2/gateways/IL2GatewayRouter.sol " ;
6
6
import "@scroll-tech/contracts/libraries/IScrollMessenger.sol " ;
7
7
8
+ interface IL2GatewayRouterExtended is IL2GatewayRouter {
9
+ function defaultERC20Gateway () external view returns (address );
10
+
11
+ function getERC20Gateway (address ) external view returns (address );
12
+ }
13
+
8
14
/**
9
15
* @title Scroll_SpokePool
10
16
* @notice Modified SpokePool contract deployed on Scroll to facilitate token transfers
11
17
* from Scroll to the HubPool
12
18
* @custom:security-contact [email protected]
13
19
*/
14
20
contract Scroll_SpokePool is SpokePool {
21
+ using SafeERC20Upgradeable for IERC20Upgradeable ;
22
+
15
23
/**
16
24
* @notice The address of the official l2GatewayRouter contract for Scroll for bridging tokens from L2 -> L1
17
25
* @dev We can find these (main/test)net deployments here: https://docs.scroll.io/en/developers/scroll-contracts/#scroll-contracts
18
26
*/
19
- IL2GatewayRouter public l2GatewayRouter;
27
+ IL2GatewayRouterExtended public l2GatewayRouter;
20
28
21
29
/**
22
30
* @notice The address of the official messenger contract for Scroll from L2 -> L1
@@ -51,7 +59,7 @@ contract Scroll_SpokePool is SpokePool {
51
59
* @param _hubPool Hub pool address to set. Can be changed by admin.
52
60
*/
53
61
function initialize (
54
- IL2GatewayRouter _l2GatewayRouter ,
62
+ IL2GatewayRouterExtended _l2GatewayRouter ,
55
63
IScrollMessenger _l2ScrollMessenger ,
56
64
uint32 _initialDepositId ,
57
65
address _crossDomainAdmin ,
@@ -66,7 +74,7 @@ contract Scroll_SpokePool is SpokePool {
66
74
* @notice Change the L2 Gateway Router. Changed only by admin.
67
75
* @param _l2GatewayRouter New address of L2 gateway router.
68
76
*/
69
- function setL2GatewayRouter (IL2GatewayRouter _l2GatewayRouter ) public onlyAdmin nonReentrant {
77
+ function setL2GatewayRouter (IL2GatewayRouterExtended _l2GatewayRouter ) public onlyAdmin nonReentrant {
70
78
_setL2GatewayRouter (_l2GatewayRouter);
71
79
}
72
80
@@ -88,9 +96,14 @@ contract Scroll_SpokePool is SpokePool {
88
96
* @param l2TokenAddress Address of the token to bridge.
89
97
*/
90
98
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.
94
107
// Note: This happens due to the L2GatewayRouter.getERC20Gateway() call
95
108
l2GatewayRouter.withdrawERC20 (
96
109
l2TokenAddress,
@@ -116,7 +129,7 @@ contract Scroll_SpokePool is SpokePool {
116
129
require (_xDomainSender == crossDomainAdmin, "Sender must be admin " );
117
130
}
118
131
119
- function _setL2GatewayRouter (IL2GatewayRouter _l2GatewayRouter ) internal {
132
+ function _setL2GatewayRouter (IL2GatewayRouterExtended _l2GatewayRouter ) internal {
120
133
address oldL2GatewayRouter = address (l2GatewayRouter);
121
134
l2GatewayRouter = _l2GatewayRouter;
122
135
emit SetL2GatewayRouter (address (_l2GatewayRouter), oldL2GatewayRouter);
0 commit comments