function testIfSignerCanWithdrawTokensToArbitraryAddress() public {
// user deposits 10 tokens to Vault
vm.startPrank(user);
uint256 depositAmount = 10e18
uint256 userInitialBalance = token.balanceOf(address(user));
token.approve(address(tokenBridge), depositAmount);
tokenBridge.depositTokensToL2(user, userInL2, depositAmount);
assertEq(token.balanceOf(address(vault)), depositAmount);
assertEq(token.balanceOf(address(user)), userInitialBalance - depositAmount);
vm.stopPrank();
// operator withdraws 10 tokens from Vault to arbitrary address
address addr = makeAddr("randomAddress")
(uint8 v, bytes32 r, bytes32 s) = _signMessage(_getTokenWithdrawalMessage(addr, depositAmount), operator.key);
tokenBridge.withdrawTokensToL1(addr, depositAmount, v,r,s);
assertEq(token.balanceOf(addr), depositAmount);
// Mitigate by holding a mapping of user => amount deposited
}
@@ -15,11 +15,13 @@ import { L1Vault } from "./L1Vault.sol";
contract L1BossBridge is Ownable, Pausable, ReentrancyGuard {
using SafeERC20 for IERC20;
uint256 public DEPOSIT_LIMIT = 100_000 ether;
IERC20 public immutable token;
L1Vault public immutable vault;
mapping(address account => bool isSigner) public signers;
+ mapping(address account => uint256 amount) public amountDeposited;
error L1BossBridge__DepositLimitReached();
error L1BossBridge__Unauthorized();
@@ -42,7 +44,7 @@ contract L1BossBridge is Ownable, Pausable, ReentrancyGuard {
_unpause();
}
function setSigner(address account, bool enabled) external onlyOwner {
signers[account] = enabled;
}
@@ -59,6 +61,7 @@ contract L1BossBridge is Ownable, Pausable, ReentrancyGuard {
if (token.balanceOf(address(vault)) + amount > DEPOSIT_LIMIT) {
revert L1BossBridge__DepositLimitReached();
}
+ amountDeposited[from] += amount;
token.safeTransferFrom(from, address(vault), amount);
// Our off-chain service picks up this event and mints the corresponding tokens on L2
@@ -76,7 +79,12 @@ contract L1BossBridge is Ownable, Pausable, ReentrancyGuard {
* @param r The r value of the signature
* @param s The s value of the signature
*/
function withdrawTokensToL1(address to, uint256 amount, uint8 v, bytes32 r, bytes32 s) external {
+ require(amount <= amountDeposited[to], "L1BossBridge: amount is less than deposited");
+ amountDeposited[to] -= amount;
sendToL1(
v,
r,
s,
abi.encode(
address(token),
0, // value
abi.encodeCall(IERC20.transferFrom, (address(vault), to, amount))
)
);
}