• We write our contracts in Solidity.
  • We build, test, format, and deploy the contracts with Foundry.
  • We adhere to most of the best practices mentioned in the Foundry Book, including:
    • Importing specific symbols instead of entire Solidity files
    • External dependencies are imported first, then “src”, then “test”
    • Code is formatted using forge fmt
    • Each test contract serves as a “describe” block to test a function
  • We follow a naming style that is consistent throughout the codebase:
    • Contracts, interfaces, and libraries are in PascalCase
    • Constants are in SNAKE_CASE
    • Functions and variables and are in camelCase
    • Internal and private functions and variables start with _
    • To avoid shadowing state variables, function parameters have a trailing _
    • Errors follow the convention ContractName>_<ErrorName>
    • Test functions follow the convention test(Fork)?(Fuzz)?_(RevertWhen_){1})?\\w{1,}; a comprehensive list of valid and invalid examples can be found here.
    • Directories are in kebab-case
    • File names are in either PascalCase or camelCase
    • Test file names end in .t.sol, while scripts end in .s.sol
  • We adhere to the Checks-Effects-Interactions and Function Requirements-Effects-Interactions + Protocol Invariants patterns (to the extent possible).
  • We write concrete tests using Bulloak, adhering to the Branching Tree Technique.
  • We lint all Solidity code with Solhint.
  • We document every contract, interface, library, function, and variable with comprehensive NatSpec comments.
  • We annotate almost all lines in src/ with comments that explain what that bit of code does. Some annotations might come across as a little verbose, but we think that explicitness is important in financial software like smart contracts.