The ExploitPoCTest contract is designed to test potential exploits in the Market contract. It contains four test functions, each simulating a different exploit scenario:
-
testNormalBorrowLiquidate: This function simulates a normal borrowing and liquidation scenario to ensure system integrity. It sets up a normal user interaction with the market, borrows under normal conditions, and tests the liquidation process.
-
testExploitSequence: This function attempts to simulate an exploit scenario to test system resilience. It artificially manipulates the price in the Oracle contract, borrows near the daily limit, triggers liquidation, and tests if another borrow is allowed post-exploit.
-
testSustainedPriceManipulation: This function simulates a sustained price manipulation scenario to test the system's response. It artificially sets a high price in the Oracle contract, borrows near the limit based on the inflated price, and tests the system's response to repeated price changes.
-
testFlashLoanPriceManipulationExploit: This function tests a specific exploit scenario involving flash loans and price manipulation. It takes out a flash loan, manipulates the oracle price, borrows close to the daily limit, triggers liquidation, re-borrows immediately, attempts over-borrowing based on the inflated price, and repays the flash loan.
Breaking down each exploit into formal logic:
-
testNormalBorrowLiquidate:
- Given: A normal user interaction with the market, a set daily borrow limit, and a set oracle price.
- When: The user borrows under normal conditions and the liquidation process is triggered.
- Then: The system should enforce the daily borrow limit and correctly calculate the liquidation reward.
-
testExploitSequence:
- Given: An artificially manipulated oracle price, a set daily borrow limit, and a borrower.
- When: The borrower borrows near the daily limit, and the liquidation process is triggered.
- Then: The system should enforce the daily borrow limit and correctly calculate the liquidation reward. Additionally, the system should not allow another borrow post-exploit.
-
testSustainedPriceManipulation:
- Given: A sustained artificially manipulated oracle price, a set daily borrow limit, and a borrower.
- When: The borrower borrows near the limit based on the inflated price, and the liquidation process is triggered repeatedly.
- Then: The system should enforce the daily borrow limit and correctly calculate the liquidation reward. Additionally, the system should not allow over-borrowing based on the inflated price.
-
testFlashLoanPriceManipulationExploit:
- Given: A flash loan, an artificially manipulated oracle price, a set daily borrow limit, and a borrower.
- When: The borrower takes out a flash loan, manipulates the oracle price, borrows close to the daily limit, triggers liquidation, re-borrows immediately, attempts over-borrowing based on the inflated price, and repays the flash loan.
- Then: The system should enforce the daily borrow limit and correctly calculate the liquidation reward. Additionally, the system should not allow over-borrowing based on the inflated price.
Each exploit scenario is designed to test the system's response to specific manipulations and attacks. By breaking down the exploits into formal logic, we can better understand the expected behavior of the system under different conditions.
To run the tests in the ExploitPoCTest contract, you'll need to use the Foundry testing framework, which includes tools like forge. Here’s a step-by-step guide on how to execute these tests:
-
Install Foundry
- If Foundry is not installed, you can install it using the following shell command:
curl -L https://foundry.paradigm.xyz | bash foundryup
- If Foundry is not installed, you can install it using the following shell command:
-
Navigate to Your Project Directory
- Change to the directory where your Solidity project and the
ExploitPoCTest
contract are located.
- Change to the directory where your Solidity project and the
-
Compile the Contracts
- Compile your Solidity contracts to ensure all artifacts are up to date:
forge build
- Compile your Solidity contracts to ensure all artifacts are up to date:
-
Run the Tests
- Execute the tests using the
forge test
command. You can run all tests or specify a particular test. - To run all tests:
forge test
- To run a specific test, use the
--match-test
flag followed by the name of the test function:forge test --match-test testNormalBorrowLiquidate
- Execute the tests using the
-
Review the Output
- Foundry will execute the tests and provide a report on the console. This report includes information on which tests passed or failed and any errors or logs generated during the test execution.
-
Debugging (if necessary)
- If any tests fail or behave unexpectedly, you can use
forge
debug tools or add logging statements (console.log
) in your Solidity code to help diagnose issues.
- If any tests fail or behave unexpectedly, you can use
Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.
Foundry consists of:
- Forge: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- Cast: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- Anvil: Local Ethereum node, akin to Ganache, Hardhat Network.
- Chisel: Fast, utilitarian, and verbose solidity REPL.
$ forge build
$ forge test
$ forge fmt
$ forge snapshot
$ anvil
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
$ cast <subcommand>
$ forge --help
$ anvil --help
$ cast --help