Skip to content

Commit

Permalink
Merge branch 'main' into remove-redundancy
Browse files Browse the repository at this point in the history
  • Loading branch information
plotchy authored Jun 26, 2023
2 parents 2657ce1 + 8044ca4 commit 6b32d79
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 23 deletions.
48 changes: 38 additions & 10 deletions audit-readiness-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,49 @@

- [ ] Use the [latest](https://docs.soliditylang.org/en/latest/) major version of Solidity.
- [ ] Use known/established libraries where possible. [OpenZeppelin contracts](https://github.com/OpenZeppelin/openzeppelin-contracts/) are preferred because they prioritize security above all else, and most auditors are already familiar with them. [Solmate contracts](https://github.com/Rari-Capital/solmate) can be a good alternative for functions where gas optimization is paramount.
- [ ] Contracts compile without any errors or warnings from the compiler.
- [ ] Have tests for "happy path" user stories and tests that expect reverts for actions that are supposed to fail. All tests should be passing.
- [ ] Incorporate fuzz tests. Fuzzing has proven to be highly effective in uncovering bugs. Tools like [Foundry](https://github.com/foundry-rs/foundry) and [Echidna](https://github.com/crytic/echidna) allow both stateless and stateful fuzzing. The [Foundry Invariants reference guide](https://book.getfoundry.sh/forge/invariant-testing?highlight=invariant#invariant-testing) provides an overview of how to set up your contract invariants for fuzzing. If you're using [Hardhat](https://github.com/NomicFoundation/hardhat), it is worthwhile to also include one of the above tools to enhance your testing capabilities.
- [ ] Run a static analysis tool ([Slither](https://github.com/crytic/slither) preferred, [MythX](https://mythx.io/) is an alternative) on your code and consider what it tells you. They very often raise flags for non-issues, but they can sometimes catch low-hanging fruit, so it's worth doing.
- [ ] Prepare the deploy script and mock upgrade scripts (if applicable) and include them as part of audit scope. Deployments and upgrades are as important as runtime code and require the same amount of security attention.
- [ ] Document all functions. Use [NatSpec documentation](https://docs.soliditylang.org/en/develop/natspec-format.html) for `public`/`external` functions. Consider this part of the public interface of the contract.
- [ ] Any `public` function that can be made `external` should be made `external`. This is not just a gas consideration, but it also reduces the cognitive overhead for auditors because it reduces the number of possible contexts in which the function can be called.
- [ ] Have tests for all "happy path" user stories. All tests should be passing.
- [ ] Use the [Checks-Effects-Interactions pattern](https://docs.soliditylang.org/en/v0.8.13/security-considerations.html#use-the-checks-effects-interactions-pattern) everywhere possible. Otherwise use reentrancy guards. Treat all token and ETH transfers as 'interactions'.
- [ ] Contracts compile without any errors or warnings from the compiler.
- [ ] Run the code through a spellchecker.
- [ ] Avoid using assembly as much as possible. Use of assembly increases audit times because it throws away Solidity's guardrails and must be checked much more carefully.
- [ ] Document use of `unchecked`. Concretely describe *why* it is safe to not perform arithmetic checks on each code block. Preferably for each operation.
- [ ] Run the code through a spellchecker.
- [ ] Run a static analysis tool ([Slither](https://github.com/crytic/slither) preferred, [MythX](https://mythx.io/) is an alternative) on your code and consider what it tells you. They very often raise flags for non-issues, but they can sometimes catch low-hanging fruit, so it's worth doing.
- [ ] Any `public` function that can be made `external` should be made `external`. This is not just a gas consideration, but it also reduces the cognitive overhead for auditors because it reduces the number of possible contexts in which the function can be called.
- [ ] Use the [Checks-Effects-Interactions pattern](https://docs.soliditylang.org/en/v0.8.13/security-considerations.html#use-the-checks-effects-interactions-pattern) everywhere possible. Otherwise use reentrancy guards. Treat all token and ETH transfers as 'interactions'.
- [ ] Have at least one trusted Solidity dev or security person outside your organization sanity check your contracts. If your code is a tire fire and in need of major changes, you want to hear about that early and from a trusted friend (for free) rather than after an expensive audit.


### Nice to haves

- [ ] If you are using [Foundry](https://github.com/foundry-rs/foundry), **strongly** recommend using fuzz tests. There is low additional overhead and highest likelihood of finding bugs using fuzzing. If you are using hardhat, consider adding Foundry for this functionality.
- [ ] Write negative tests. E.g., if users should NOT be able to withdraw within 100 blocks of depositing, then write a test where a users tries to withdraw early and make sure the user's attempt fails.
- [ ] You can also try to use formal verification tools to verify the invariants, but be aware that -- in practice -- current formal verification tools are rarely useful for anything non-trivial.
- [ ] Write down your security assumptions. This doesn't have to be super formal. E.g., "We assume that the `owner` is not malicious, that the Chainlink oracles won't lie about the token price, that the Chainlink oracles will always report the price at least once every 24 hours, that all tokens that the `owner` approves are ERC20-compliant tokens with no transfer hooks, and that there will never be a chain reorg of more than 30 blocks". This helps you understand how things could possibly go wrong *even if your contracts are bug-free*. Auditors may also be able to tell you whether or not your assumptions are realistic. They may also be able point out assumptions you're making that you didn't realize you were making.
- [ ] Use formal verification tools to verify the invariants, but be aware that -- in practice -- current formal verification tools aren't a silver bullet and have some edge cases that aren't handled. [Certora](https://www.certora.com/) and [Runtime Verification](https://runtimeverification.com/) are examples of commonly used (paid) tools in this category.
- [ ] Write down your security assumptions. This doesn't have to be super formal. E.g., "We assume that the `owner` is not malicious, that the Chainlink oracles won't lie about the token price, that the Chainlink oracles will always report the price at least once every 24 hours, that all tokens that the `owner` approves are ERC20-compliant tokens with no transfer hooks, and that there will never be a chain reorg of more than 30 blocks." This helps you understand how things could possibly go wrong *even if your contracts are bug-free*. Good auditors will be able to help you understand you whether your assumptions are realistic. They may also be able point out assumptions you're making that you didn't realize you were making.
- [ ] If you're unsure about something in your own code, or there are areas where you'd like auditors to spend more time, make a list of these to share with the auditors.
- [ ] Add scoping details for auditors. The form used in preparation for [Code4rena](https://code4rena.com/) is provided as an example in the collapsible section below.
<details> <summary>Audit Scoping Details</summary>

- If you have a public code repo, please share it here:
- 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.":
</details>

9 changes: 4 additions & 5 deletions development-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ You may have millions of dollars at risk already, or will after launch. As such,
- Now that you are pretty confident in your implementation, throw a monkey at it. A good fuzz test should consider all valid inputs, and include as many state transition assertions as possible (think: is this function monotonically in/decreasing, should it be always less than something else, etc.)
8. Move back to step 4 if any bugs are found
9. Write integration tests
- Your feature now likely does exactly what you think it does. In a complex system, that is not enough. Ideally you have tested how it affects the entire system as well. Invariant tests are coming soon to [Foundry](https://github.com/foundry-rs/foundry), which should help integration style tests, but make do with what you can with fuzz tests on a broader basis (not just for a single function)
- Your feature now likely does exactly what you think it does. In a complex system, that is not enough. Ideally you have tested how it affects the entire system as well. Stateful testing with [Foundry](https://github.com/foundry-rs/foundry) and [Echidna](https://github.com/crytic/echidna) allows you to test system-wide invariants.
10. Move back to step 4 if any bugs are found
11. Cleanup documentation
12. Setup CI
Expand All @@ -74,13 +74,12 @@ You may have millions of dollars at risk already, or will after launch. As such,
- The implementer is just the first line of defense. If you are a reviewer, confirm that the implementer followed the above principals (test-per-state-transition, test-per-revert, fuzz test, and integration test)
- Review the documentation and ensure the implementation matches the documented behavior. If it does not, touch base with the implementer and confirm which needs to be updated
- Ensure CI passes
- Check common missteps ([reentrancy, checks-effects-interactions pattern, etc](https://docs.soliditylang.org/en/v0.8.13/security-considerations.html#pitfalls))
- Check common missteps ([reentrancy, checks-effects-interactions pattern, etc](https://docs.soliditylang.org/en/latest/security-considerations.html#pitfalls))
## Deployment
14. Write a deployment script
- Write the deployment script
- Most likely Foundry has scripting ready when you are reading this. Check out this [PR](https://github.com/foundry-rs/foundry/pull/1208)
- Foundry has a [scripting guide](https://book.getfoundry.sh/tutorials/solidity-scripting) to test your deployment on local forks.
15. Write a deployment test
- Ensure deployment goes exactly as planned by writing a test testing *every state transition* and make sure no changes unexpectedly happen. One way to accomplish this is the `record` cheatcode. If performing an upgrade to an existing protocol, create a list of your entire protocol's addresses, call record, perform the upgrade. Then, call `accesses` for each address of your protocol. Ensure there are no slots/addresses that unexpectedly changed
16. Have an audit performed
Expand All @@ -90,7 +89,7 @@ You may have millions of dollars at risk already, or will after launch. As such,
17. Implement audit fixes
18. Setup monitoring service
- Have an internal tool that monitors important aspects of your system
- Use tools like [Check the Chain](https://github.com/fei-protocol/checkthechain) + [Grafana](https://grafana.com/), or use an off-the-shelf monitoring tool like [Tenderly](https://tenderly.co/alerting) or OpenZeppelin's [Defender Sentinels](https://www.openzeppelin.com/defender).
- Use tools like [Check the Chain](https://github.com/checkthechain/checkthechain) + [Grafana](https://grafana.com/), or use an off-the-shelf monitoring tool like [Tenderly](https://tenderly.co/alerting) or OpenZeppelin's [Defender Sentinels](https://www.openzeppelin.com/defender).
19. Prepare/update your [Incident Response Plan](incident-response-plan-template.md)
20. Deploy the contract(s)
- Congrats, you probably just crushed 99% of Solidity devs in terms of a secure development + deployment
Expand Down
11 changes: 6 additions & 5 deletions incident-response-plan-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ War Room Participants: **[*Names and contact info*]**
## Immediate Steps

- [ ] **Review exploit** transactions to identify vulnerability - **[*Person responsible*]**
- Tools used:
- [Foundry Transaction Replay Trace/Debugger](https://book.getfoundry.sh/reference/cast/cast-run.html#cast-run)
- [Tenderly Debugger](https://dashboard.tenderly.co/tx/mainnet/0xf427afc17bd30a84f4b47dc2eaa176115cf28bdea1110245d3b0948ca3b6595c/debugger)
- [ethtx.info](https://ethtx.info)
- Tools used:
- [Phalcon Tx Explorer](https://explorer.phalcon.xyz/)
- [Foundry Transaction Replay Trace/Debugger](https://book.getfoundry.sh/reference/cast/cast-run.html#cast-run)
- [Tenderly Debugger](https://dashboard.tenderly.co/tx/mainnet/0xf427afc17bd30a84f4b47dc2eaa176115cf28bdea1110245d3b0948ca3b6595c/debugger)
- [ ] **Pause contracts** (if possible), take other defensive action, consider offensive action (i.e. whitehat rescues) - **[*Person responsible for coordinating*]**
- Steps:
- **[*Who, how, what addresses*]**
Expand All @@ -32,9 +32,10 @@ War Room Participants: **[*Names and contact info*]**
- **[*List of past auditors and their contact info or location of shared channel*]**
- Your auditors will want to assist to the extent they are able, even if primarily to protect their own reputations
- DO NOT LET ANYONE OUTSIDE OF YOUR CIRCLE OF TRUST INTO THE WAR ROOM
- Even if attackers have successfully exfiltrated funds, do not assume stolen funds are unrecoverable. Immediately reach out to trusted parties including known security professionals or your venture investors for referrals to relevant law enforcement contacts, asset tracking experts, and recovery services.
- [ ] **Notify users** via relevant Social Media communication channels. Discord: **[*Person responsible*]**, Twitter: **[*Person responsible*]**
- Update regularly as meaningful new information or developments are available
- Even if nothing new is known, updates every 4 to 12 hours will help reassure your community that you are working to address the situation
- Even if nothing new is known, updates at least every 24 hours will help reassure your community that you are working to address the situation
- Run all messages by the vulnerability reviewer(s) to ensure no information is shared that inadvertently puts security at risk or commits to specific remediation before all facts are known

## After Immediate Steps Are Addressed
Expand Down
6 changes: 3 additions & 3 deletions pre-launch-security-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
- [ ] Respond to all recommended changes in your draft audit report and have the auditor publish the final version of the report including acknowledgement of your responses.
- [ ] If you received a large number of recommended changes to your code during the audit, you should strongly consider getting a second audit after you make the changes, ideally from another auditor. Audits with long lists of issues often indicate that the auditors would have found even more issues given more time.
- [ ] [Verify](https://etherscan.io/verifyContract) your contracts on Etherscan. There are automated tools in [Foundry](https://book.getfoundry.sh/forge/deploying.html?highlight=verify#verifying) or [Hardhat](https://hardhat.org/plugins/nomiclabs-hardhat-etherscan.html) that help verify for you.
- [ ] Set up a bug bounty program. [Immunefi](https://immunefi.com/) or [HackerOne](https://www.hackerone.com/) can help coordinate it. Whatever you initially consider an appropriate an appropriate bounty for a High Severity issue should probably be increased by 2-10x (post-launch, the floor should be 1% of value at risk).
- [ ] Set up monitoring and alerting. You want to be on top of what's happening with your project so you can respond quickly to security incidents. For example, you can have a script to monitor for new governance proposals and be alerted when they occur. Or, if you're using a TWAP, have a script that checks the TWAP every block, compares it against the price feed from a CEX, and alerts you if it's every different by more than 10%. Or an alert to let you know when more than 20% of the tokens in your contract have been removed in a single tx. There are a tools that you can use like [Check the Chain](https://github.com/fei-protocol/checkthechain) + [Grafana](https://grafana.com/), or use an off-the-shelf monitoring tool like [Tenderly](https://tenderly.co/alerting) or OpenZeppelin's [Defender Sentinels](https://www.openzeppelin.com/defender).
- [ ] Set up a bug bounty program. [Immunefi](https://immunefi.com/) or [HackerOne](https://www.hackerone.com/) can help coordinate it. Whatever you initially consider an appropriate bounty for a High Severity issue should probably be increased by 2-10x (post-launch, the floor should be 1% of value at risk).
- [ ] Set up monitoring and alerting. You want to be on top of what's happening with your project so you can respond quickly to security incidents. For example, you can have a script to monitor for new governance proposals and be alerted when they occur. Or, if you're using a TWAP, have a script that checks the TWAP every block, compares it against the price feed from a CEX, and alerts you if it's ever different by more than 10%. Or an alert to let you know when more than 20% of the tokens in your contract have been removed in a single tx. There are tools that you can use like [Check the Chain](https://github.com/checkthechain/checkthechain) + [Grafana](https://grafana.com/), or use an off-the-shelf monitoring tool like [Tenderly](https://tenderly.co/alerting) or OpenZeppelin's [Defender Sentinels](https://www.openzeppelin.com/defender).
- [ ] Prepare emergency action scripts to pause contracts or take other defensive actions in the event of an exploit.
- [ ] Create an incident response plan. In the event of a hack, you want to know ahead of time who will be in the war room, which platform(s) (e.g., Discord, Signal, etc) and which channels you'll use to communicate, and how to enact defensive actions. Having this all in a doc somewhere will be helpful so you can rely on it when the adrenaline is clouding your judgment. You can use [this template](https://github.com/nascentxyz/simple-security-toolkit/blob/main/incident-response-plan-template.md) to prepare.
- [ ] Create an incident response plan. In the event of a hack, you want to know ahead of time who will be in the war room, which platform(s) (e.g., Discord, Signal, etc) and which channels you'll use to communicate, and how to enact defensive actions. Having this all in a doc somewhere will be helpful so you can rely on it when the adrenaline is clouding your judgment. You can use [this template](https://github.com/nascentxyz/simple-security-toolkit/blob/main/incident-response-plan-template.md) to prepare.

0 comments on commit 6b32d79

Please sign in to comment.