-
Notifications
You must be signed in to change notification settings - Fork 347
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
119 changed files
with
5,624 additions
and
580 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
version: 2 | ||
updates: | ||
- package-ecosystem: "github-actions" | ||
directory: "/" | ||
schedule: | ||
interval: "daily" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
name: Echidna | ||
|
||
on: | ||
push: | ||
branches: | ||
- master | ||
- dev | ||
pull_request: | ||
schedule: | ||
# run CI every day even if no PRs/merges occur | ||
- cron: '0 12 * * *' | ||
|
||
jobs: | ||
tests: | ||
name: ${{ matrix.name }} | ||
continue-on-error: ${{ matrix.flaky == true }} | ||
runs-on: ubuntu-22.04 | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
include: | ||
- name: Exercise 1 | ||
workdir: program-analysis/echidna/exercises/exercise1/ | ||
files: solution.sol | ||
contract: TestToken | ||
outcome: failure | ||
expected: 'echidna_test_balance:\s*failed' | ||
- name: Exercise 2 | ||
workdir: program-analysis/echidna/exercises/exercise2/ | ||
files: solution.sol | ||
contract: TestToken | ||
outcome: failure | ||
expected: 'echidna_no_transfer:\s*failed' | ||
- name: Exercise 3 | ||
workdir: program-analysis/echidna/exercises/exercise3/ | ||
files: solution.sol | ||
contract: TestToken | ||
outcome: failure | ||
expected: 'echidna_test_balance:\s*failed' | ||
- name: Exercise 4 | ||
workdir: program-analysis/echidna/exercises/exercise4/ | ||
files: solution.sol | ||
config: config.yaml | ||
contract: Token | ||
outcome: failure | ||
expected: 'transfer(address,uint256):\s*failed' | ||
- name: TestToken | ||
workdir: program-analysis/echidna/example/ | ||
files: testtoken.sol | ||
contract: TestToken | ||
outcome: failure | ||
expected: 'echidna_balance_under_1000:\s*failed' | ||
- name: Gas estimation | ||
workdir: program-analysis/echidna/example/ | ||
files: gas.sol | ||
config: gas.yaml | ||
outcome: success | ||
expected: 'f(42,123,' | ||
flaky: true | ||
- name: Multi | ||
workdir: program-analysis/echidna/example/ | ||
files: multi.sol | ||
config: filter.yaml | ||
outcome: failure | ||
expected: 'echidna_state4:\s*failed' | ||
- name: Assert | ||
workdir: program-analysis/echidna/example/ | ||
files: assert.sol | ||
config: assert.yaml | ||
outcome: failure | ||
expected: 'inc(uint256):\s*failed' | ||
- name: PopsicleBroken | ||
workdir: program-analysis/echidna/example/ | ||
files: PopsicleBroken.sol | ||
solc-version: 0.8.4 | ||
config: Popsicle.yaml | ||
contract: PopsicleBroken | ||
outcome: failure | ||
expected: 'totalBalanceAfterTransferIsPreserved(address,uint256):\s*failed' | ||
- name: PopsicleFixed | ||
workdir: program-analysis/echidna/example/ | ||
files: PopsicleFixed.sol | ||
solc-version: 0.8.4 | ||
config: Popsicle.yaml | ||
contract: PopsicleFixed | ||
outcome: success | ||
expected: 'totalBalanceAfterTransferIsPreserved(address,uint256):\s*passed' | ||
- name: TestDepositWithPermit | ||
workdir: program-analysis/echidna/example/ | ||
files: TestDepositWithPermit.sol | ||
solc-version: 0.8.0 | ||
config: testdeposit.yaml | ||
contract: TestDepositWithPermit | ||
outcome: success | ||
expected: 'testERC20PermitDeposit(uint256):\s*passed' | ||
|
||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v3 | ||
- name: Run Echidna | ||
uses: crytic/echidna-action@v2 | ||
id: echidna | ||
continue-on-error: true | ||
with: | ||
files: ${{ matrix.files }} | ||
contract: ${{ matrix.contract }} | ||
config: ${{ matrix.config }} | ||
output-file: ${{ matrix.files }}.out | ||
solc-version: ${{ matrix.solc-version || '0.5.11' }} | ||
echidna-workdir: ${{ matrix.workdir }} | ||
echidna-version: edge | ||
- name: Verify that the exit code is correct | ||
run: | | ||
if [[ ${{ steps.echidna.outcome }} = ${{ matrix.outcome }} ]]; then | ||
echo "Outcome matches" | ||
else | ||
echo "Outcome mismatch. Expected ${{ matrix.outcome }} but got ${{ steps.echidna.outcome }}" | ||
exit 1 | ||
fi | ||
- name: Verify that the output is correct | ||
run: | | ||
if grep -q "${{ matrix.expected }}" "${{ steps.echidna.outputs.output-file }}"; then | ||
echo "Output matches" | ||
else | ||
echo "Output mismatch. Expected something matching '${{ matrix.expected }}'. Got the following:" | ||
cat "${{ steps.echidna.outputs.output-file }}" | ||
exit 1 | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Building Secure Smart Contracts | ||
|
||
![](https://github.com/crytic/building-secure-contracts/workflows/CI/badge.svg) ![](https://github.com/crytic/building-secure-contracts/workflows/Echidna/badge.svg) | ||
|
||
Follow our guidelines and best practices to write secure smart contracts. | ||
|
||
**Table of contents:** | ||
|
||
- [Development guidelines](./development-guidelines) | ||
- [High-level best practices](./development-guidelines/guidelines.md): High-level best-practices for all smart contracts | ||
- [Incident Response Recommendations](./development-guidelines/incident_response.md): Guidelines on how to formulate an incident response plan | ||
- [Secure development workflow](./development-guidelines/workflow.md): A rough, high-level process to follow while you write code | ||
- [Token integration checklist](./development-guidelines/token_integration.md): What to check when interacting with arbitrary token | ||
- [Learn EVM](./learn_evm): EVM technical knowledge | ||
- [EIPs - forks](./learn_evm/eips_forks.md): summarize the EIPs included in each fork | ||
- [Program analysis](./program-analysis): How to use automated tools to secure contracts | ||
- [Echidna](./program-analysis/echidna): a fuzzer that will check your contract's properties. | ||
- [Slither](./program-analysis/slither): a static analyzer avaialable through a CLI and scriptable interface. | ||
- [Manticore](./program-analysis/manticore): a symbolic execution engine that can prove the correctness properties. | ||
- For each tool, this training material will provide: | ||
- a theoretical introduction, a walkthrough of its API, and a set of exercises. | ||
- exercises expected to require ~two hours to practically learn its operation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,96 +1,6 @@ | ||
# Development Guidelines | ||
List of smart contract development best practices | ||
|
||
The following recommendations describe high-level best pratices. | ||
|
||
## Design Guidelines | ||
|
||
The design of the contract should be discussed ahead of time, prior writing any line of code. | ||
|
||
### Documentation and specification | ||
|
||
Documentation can be written at different levels, and should be updated while implementing the contracts: | ||
|
||
- **A plain English description of the system**, describing what the contracts do and any assumptions on the codebase. | ||
|
||
- **Schema and architectural diagrams**, including the contracts interactions, and the state machine of the system. [Slither printers](https://github.com/crytic/slither/wiki/Printer-documentation) will help to generate these schemas. | ||
|
||
- **Thorough code documentation**, the [Natspec format](https://solidity.readthedocs.io/en/develop/natspec-format.html) can be used for Solidity. | ||
|
||
## Onchain vs Offchain computation | ||
|
||
- **Put as much code as you can offchain.** Keep the onchain layer small. Rely on offchain code for any data pre-processing for which the result can be easily verified onchain. You need an ordered list? Sort the list offchain, and check only its order onchain. | ||
|
||
## Upgradeability | ||
|
||
We discussed the different upgradeability solutions in [our blogpost](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/). The choice of upgradeable contract or not must be deliberate prior coding. The decision will influence how you structure our code. The summary is: | ||
|
||
- **Favor [contract’s migration](https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/) over upgradeability.** Migrations system have the same advantages than upgradeable, without their drawbacks. | ||
|
||
- **Use the data separation pattern over the delegatecallproxy one.** If your project has a clear abstraction separation, upgradeability using the data separation pattern will necessitate only a few adjustments. The delegatecallproxy requires EVM expertise and is highly error-prone. | ||
|
||
- **Document the migration/upgrade procedure before the deployment.** If you have to react under stress without any guidelines, you will make mistakes. Write the procedure to follow ahead of time. It should include: | ||
- What are the calls to make to initiate the new contracts. | ||
- Where are stored the keys, and how to access them. | ||
- How to check the deployment. A post-deployment script should be prepared, and fully tested. | ||
|
||
# Implementation Guidelines | ||
|
||
The main advice to keep in mind is to **strive for simplicity.** Always use the simplest solution that fits your purpose. Always keep in mind that anyone should be able to understand your solution. | ||
|
||
## Function Composition | ||
|
||
The architecture of your codebase will also heavily influence the ease to review your code. | ||
|
||
- **Split the logic of your system**, either through multiple contracts or by grouping similar functions together (ex: authentification, arithmetic, …). It will ease targeting the features of the code | ||
|
||
- **Write small functions, with a clear purpose.** Small code is simpler to review and allow the testing of individual components. | ||
|
||
## Inheritance | ||
|
||
- **Keep the inheritance manageable.** While inheritance should be used to divide the logic, your project should aim to minimize the depth and the width of the inheritance tree. | ||
|
||
- **Use Slither’s [inheritance printer](https://github.com/crytic/slither/wiki/Printer-documentation#inheritance-graph) to check the contracts’ hierarchy.** The inheritance printer will help you to watch the hierarchy grows. | ||
|
||
## Events | ||
|
||
- **Log any crucial operation.** Events will help to debug the contract during the development, and monitor it after its deployment. | ||
|
||
## Blockchain pitfalls | ||
|
||
- **Be aware of the most common vulnerabilities patterns.** There are many online resources to learn about common issues, such as [Ethernaut CTF](https://ethernaut.openzeppelin.com/), [Capture the Ether](https://capturetheether.com/), or [Not so smart contract](https://github.com/crytic/not-so-smart-contracts/). | ||
|
||
- **Be aware of the warnings sections in the [Solidity documentation](https://solidity.readthedocs.io/en/latest/).** The warnings sections will inform you about not obvious behavior of the language. | ||
|
||
## Dependencies | ||
|
||
- **Use well-tested libraries.** Importing code from well-tested libraries will reduce the likelihood for you to write buggy code. If you want to write an ERC20 contract, use [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20). | ||
|
||
- **Use a dependencies manager, avoid copy-and-paste of code.** If you rely on an external source, be sure to be up to date with the original codebase. | ||
|
||
## Testing and Verifying | ||
|
||
- **Write thorough unit-tests.** An extensive test suite is crucial to build high-quality software. | ||
|
||
- **Write [Slither](https://github.com/crytic/slither), [Echidna](https://github.com/crytic/echidna) and [Manticore](https://github.com/trailofbits/manticore) custom checks and properties.** Automated tools will help you to ensure your contracts is secure. The content of this repository will help you to write efficient checks and properties. | ||
|
||
- **Use [crytic.io](https://crytic.io/).** Crytic will give you access to Slither’s private detectors, and will provide github integration. | ||
|
||
## Solidity | ||
|
||
- **Favor Solidity 0.5 over 0.4 and 0.6.** Solidity 0.5 is overall more secure and has better inbuilt practices and 0.4. Solidity 0.6 is too young to be used in production. | ||
|
||
- **Use a stable compiler’s version to compile, use the latest to check for warnings.** You should check that your code leads to no warning with the latest compiler version. Solidity compiler has a fast release cycle, and has a history of compiler bugs, as a result, we recommend to not use the latest version for deployment (see Slither’s [solc version recommendation](https://github.com/crytic/slither/wiki/Detector-Documentation#recommendation-33)). | ||
|
||
- **Do not use inline assembly.** Assembly requires EVM expertise, if you do not master the yellow paper, do not write EVM code. | ||
|
||
## Post development Guidelines | ||
|
||
Once the contract has been developed, consider to: | ||
|
||
- **Monitor your contracts.** Watch the contracts’ logs, and be ready to react in case of contracts or wallet compromise. | ||
|
||
- **Add your contact info to [blockchain-security-contacts](https://github.com/crytic/blockchain-security-contacts).** The list will help third-parties to contact and coordinate with you if any security flaw is discovered. | ||
|
||
- **Secure the wallets of privileged users.** Follow the [best practices](https://blog.trailofbits.com/2018/11/27/10-rules-for-the-secure-use-of-cryptocurrency-hardware-wallets/) to store the wallets. | ||
|
||
- **Have a response to incident plan.** Take in consideration that you can be compromised. Even if your contracts are free of bugs, an attacker can take control of the contract’s owner keys. | ||
- [High-level best practices](./guidelines.md): High-level best-practices for all smart contracts | ||
- [Token integration checklist](./token_integration.md): What to check when interacting with arbitrary tokens | ||
- [Incident Response Recommendations](./incident_response.md): Guidelines on how to formulate an incident response plan | ||
- [Secure development workflow](./workflow.md): A rough, high-level process to follow while you write code |
Oops, something went wrong.