- Forge-std
- Open Zeppelin
- Interact with blockchain storage
forge install foundry-rs/forge-stdforge install OpenZeppelin/openzeppelin-contractsforge install OpenZeppelin/openzeppelin-contracts-upgradeablefoundry.toml (Remappings)
Example:
[profile.default]
# ... other settings
remappings = [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/" # Also needed for standard contracts]curl -X POST [RPC_URL] -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "method":"eth_getStorageAt", "params": ["[CONTRACT_ADDRESS]","[NUM_SLOT-IN-HEX]","latest"],"id":1}'[RPC_UR], [CONTRACT_ADDRESS], [NUM_SLOT-IN-HEX]
- Graph creation
- Action to function trace 1. All imports to 1 file (
surya graph [PATH/CONTRACT_NAME].solmkdir -p flatten)
forge flatten src/[CONTRACT_NAME].sol > flat/[CONTRACT_NAME].flatten.solftrace with flatten
surya ftrace "[CONTRACT_NAME]::[FUNCTION_NAME]" [all|external|internal] flatten/[CONTRACT_NAME].flat.sol- hex to decimal
- hex to string
- keccak256 with string
- Function signature
- ABI encode with args
- ABI encode without sig, only args
- Check storage
- Bytes32 to string
- Bytes4 (signature) to string
cast --to-dec [hex]cast --abi-decode "myFunc()(string)" 0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014416e79206b696e64206f6620636f6f6b69657321000000000000000000000000myFunc() is random name. Guess cast just need (unexisted)function in command.
cast keccak "..."cast sig "func(uint256,address)"cast calldata "func(...)" arg1 arg2cast calldata "func(...)" arg1 arg2cast storage [CONTRACT_ADDRESS] [NUM_SLOT] --rpc-url [RPC_URL]cast parse-bytes32-string [TARGET_BYTES]cast 4byte [sig]- Test
- Test certain function
- Gas Report
- Inspect
- To view storage layout
- To view contract`s methods
- Coverage
- Run
- Can help with
Stack too deep
forge test --match-test testFunctionName -vvv-vvv for deep verbose, --mp (match-path) to certain path contract
forge test --gas-reportforge inspect <CONTRACT_NAME> storage-layoutforge inspect <CONTRACT_NAME> methodsforge coverageforge coverage --ir-minimumbound()x: The input value from the fuzzer.min: The lower bound (inclusive) of the desired range.max: The upper bound (inclusive) of the desired range.- Another restriction for fuzzing
vm.warp()- skip some timevm.warp()- skip some blocks
The bound() function is designed to constrain the input values of fuzz tests within a specified range
Usage:
_value = bound(_value, 1, type(uint256).max);bound() function takes three uint256 arguments:
vm.assume(_value > 0);vm.warp(block.timestamp + 10 seconds);vm.roll(block.number + 100);- Ok starting time, not start from 1 (
vm.warp) - Fuzzing and assumption
modifier startAtPresentDay() {
vm.warp(1680616584);
_;
}// notSeller will be chosen randomly
function testInvalidSellerAddress(address notSeller) public {
vm.assume(notSeller != seller); // предпологается, что точно не `seller`
vm.expectRevert("not the seller");
depositContract.sellerWithdraw(notSeller);
}- Compare
stringtype
keccak256(abi.encodePacked(string1)) == keccak256(abi.encodePacked(string2))- VS Codium
- Foundry
- CLoC
- Slither
- Aderyn
- eth-security-toolbox
- upgradehub.xyz for checking smart contracts changes
- Auditors Handbook from Guadrdian Audits Lab
- Zokyo Tutorials
- workshop-fuzzing (instructions & examples)
The Rekt Test
- Do you have all actors, roles, and privileges documented?
- Do you keep documentation of all the external services, contracts, and oracles you rely on?
- Do you have a written and tested incident response plan?
- Do you document the best ways to attack your system?
- Do you perform identity verification and background checks on all employees?
- Do you have a team member with security defined in their role?
- Do you require hardware security keys for production systems?
- Does your key management system require multiple humans and physical steps?
- Do you define key invariants for your system and test them on every commit?
- Do you use the best automated tools to discover security issues in your code?
- Do you undergo external audits and maintain a vulnerability disclosure or bug bounty program?
- Have you considered and mitigated avenues for abusing users of your system?
Audit Scoping Details
- Public link code repo, if exist
- How many contracts are in scope?
- Total SLoC for these contracts?
- How many external imports are there?
- How many separate interfaces and struct definitions are there for the contracts within scope?
- Does most of your code generally use composition or inheritance?
- How many external calls?
- What is the overall line coverage percentage provided by your tests?:
- Is there a need to understand a separate part of the codebase / get context in order to audit this part of the protocol?
- If so, please describe required context
- Does it use an oracle?
- Does the token conform to the ERC20 standard?
- Do you expect ERC721, ERC777, FEE-ON-TRANSFER, REBASING or any other non-standard ERC will interact with the smart contracts?
- Are there any novel or unique curve logic or mathematical models?
- Does it use a timelock function?
- Is it an NFT?
- Does it have an AMM?
- Is it a fork of a popular project?
- Does it use rollups?
- Is it multi-chain?
- Does it use a side-chain?
- Describe any specific areas you would like addressed. E.g. Please try to break XYZ."
OWASP Smart Contract Top 10
- Access Control Vulnerabilities
- Price Oracle Manipulation
- Logic Errors
- Lack of Input Validation
- Reentrancy Attacks
- Unchecked External Calls
- Flash Loan Attacks
- Integer Overflow and Underflow
- Insecure Randomness
- Denial of Service (DoS) Attacks
Methodology
- Read docs and understand the project
- Main functionality
- Roles
- Invariants
- Static Analysis
- Dynamic analysis
- Pragma version, imports, inheritances
- State variables (visability)
- Focus on
externalandpublicfunctions Check-Effects-InteractionspatternS.E.A.R.C.H.(State, External, Access, Reentrancy, Checks, Handling) pattern- Testing (invariant tests -> stateless & stateful fuzzing, check hypotheses)
- Reporting
Steps
# STRUCTURE: FIRST HOURS OF PROTOCOL RESEARCH 1. ARCHITECTURE - read README and Deployment / addresses - find entrypoints (Router / Core / Vault / Manager) - draw diagramm 2. TRUST MODEL - who can change and what can be changable (owner, guardian, controller) - where is upgrade, pause, withdraw, mint/burn 3. USER FLOW - how regular user interact: deposit → stake → claim - which data go to в state - where is external call / callback 4. SECURITY INVARIANTS - what have to be true: balance >= shares, owner != zero, etc. - what breaks invariants 5. ATTACK SURFACE - external/public funcs without access-control - all loops (gas DoS) - all places with call.value / transfer / delegatecall / external token - where is state depends on external contracts 6. CHECKLIST (rest) - Reentrancy - Privilege escalation - Math errors (arithmetic, rounding) - Oracle manipulation - Initialization / upgrade gaps - Access Control List - Broken Logic