{"id":18542788,"url":"https://github.com/coinbase/solidity-style-guide","last_synced_at":"2026-01-27T19:05:06.894Z","repository":{"id":230478937,"uuid":"776093045","full_name":"coinbase/solidity-style-guide","owner":"coinbase","description":null,"archived":false,"fork":false,"pushed_at":"2024-04-13T16:19:09.000Z","size":114,"stargazers_count":390,"open_issues_count":0,"forks_count":19,"subscribers_count":9,"default_branch":"main","last_synced_at":"2024-04-14T12:01:20.296Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coinbase.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-03-22T17:05:38.000Z","updated_at":"2024-04-19T15:51:48.961Z","dependencies_parsed_at":"2024-03-30T02:25:33.958Z","dependency_job_id":"002829be-47c4-4dc8-8ef2-8d880c33fe4e","html_url":"https://github.com/coinbase/solidity-style-guide","commit_stats":null,"previous_names":["coinbase/solidity-style-guide"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/coinbase/solidity-style-guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fsolidity-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fsolidity-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fsolidity-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fsolidity-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coinbase","download_url":"https://codeload.github.com/coinbase/solidity-style-guide/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fsolidity-style-guide/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28819062,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T18:44:20.126Z","status":"ssl_error","status_checked_at":"2026-01-27T18:44:09.161Z","response_time":168,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T20:10:39.686Z","updated_at":"2026-01-27T19:05:06.877Z","avatar_url":"https://github.com/coinbase.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Coinbase Solidity Style Guide\n\nThis is a guide for Coinbase engineers developing EVM-based smart contracts. We use Solidity when developing such contracts, so we call it a \"Solidity Style Guide.\" This guide also covers development and testing practices. We are sharing this publicly in case it is useful to others.\n\n## Why?\n\nWe should be as specific and thorough as possible when defining our style, testing, and development practices. Any time we save not having to debate these things on pull requests is productive time that can go into other discussion and review. Following the style guide is evidence of care.\n\n![tom-sachs-gq-style-spring-2019-05](https://github.com/coinbase/solidity-style-guide/assets/6678357/9e904107-e83f-4d89-a405-d3f1394d8de4)\n\n## 1. Style\n\n### A. Unless an exception or addition is specifically noted, we follow the [Solidity Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html).\n\n### B. Exceptions\n\n#### 1. Names of internal functions in a library should not have an underscore prefix.\n\nThe style guide states\n\n\u003e Underscore Prefix for Non-external Functions and Variables\n\nOne of the motivations for this rule is that it is a helpful visual clue.\n\n\u003e Leading underscores allow you to immediately recognize the intent of such functions...\n\nWe agree that a leading underscore is a useful visual clue, and this is why we oppose using them for internal library functions that can be called from other contracts. Visually, it looks wrong.\n\n```solidity\nLibrary._function()\n```\n\nor\n\n```solidity\nusing Library for bytes\nbytes._function()\n```\n\nNote, we cannot remedy this by insisting on the use public functions. Whether a library functions are internal or external has important implications. From the [Solidity documentation](https://docs.soliditylang.org/en/latest/contracts.html#libraries)\n\n\u003e ... the code of internal library functions that are called from a contract and all functions called from therein will at compile time be included in the calling contract, and a regular JUMP call will be used instead of a DELEGATECALL.\n\nDevelopers may prefer internal functions because they are more gas efficient to call.\n\nIf a function should never be called from another contract, it should be marked private and its name should have a leading underscore.\n\n### C. Additions\n\n#### 1. Errors\n\n##### A. Prefer custom errors.\n\nCustom errors are in some cases more gas efficient and allow passing useful information.\n\n##### B. Custom error names should be CapWords style.\n\nFor example, `InsufficientBalance`.\n\n#### 2. Events\n\n##### A. Events names should be past tense.\n\nEvents should track things that _happened_ and so should be past tense. Using past tense also helps avoid naming collisions with structs or functions.\n\nWe are aware this does not follow precedent from early ERCs, like [ERC-20](https://eips.ethereum.org/EIPS/eip-20). However it does align with some more recent high profile Solidity, e.g. [1](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/976a3d53624849ecaef1231019d2052a16a39ce4/contracts/access/Ownable.sol#L33), [2](https://github.com/aave/aave-v3-core/blob/724a9ef43adf139437ba87dcbab63462394d4601/contracts/interfaces/IAaveOracle.sol#L25-L31), [3](https://github.com/ProjectOpenSea/seaport/blob/1d12e33b71b6988cbbe955373ddbc40a87bd5b16/contracts/zones/interfaces/PausableZoneEventsAndErrors.sol#L25-L41).\n\nYES:\n\n```solidity\nevent OwnerUpdated(address newOwner);\n```\n\nNO:\n\n```solidity\nevent OwnerUpdate(address newOwner);\n```\n\n##### B. Prefer `SubjectVerb` naming format.\n\nYES:\n\n```solidity\nevent OwnerUpdated(address newOwner);\n```\n\nNO:\n\n```solidity\nevent UpdatedOwner(address newOwner);\n```\n\n#### 3. Named arguments and parameters\n\n##### A. Avoid unnecessary named return arguments.\n\nIn short functions, named return arguments are unnecessary.\n\nNO:\n\n```solidity\nfunction add(uint a, uint b) public returns (uint result) {\n  result = a + b;\n}\n```\n\nNamed return arguments can be helpful in functions with multiple returned values.\n\n```solidity\nfunction validate(UserOperation calldata userOp) external returns (bytes memory context, uint256 validationData)\n```\n\nHowever, it is important to be explicit when returning early.\n\nYES:\n\n```solidity\nfunction validate(UserOperation calldata userOp) external returns (bytes memory context, uint256 validationData) {\n  context = \"\";\n  validationData = 1;\n\n  if (condition) {\n    return (context, validationData);\n  }\n}\n```\n\nNO:\n\n```solidity\nfunction validate(UserOperation calldata userOp) external returns (bytes memory context, uint256 validationData) {\n  context = \"\";\n  validationData = 1;\n  if (condition) {\n    return;\n  }\n}\n```\n\n##### B. Prefer named arguments.\n\nPassing arguments to functions, events, and errors with explicit naming is helpful for clarity, especially when the name of the variable passed does not match the parameter name.\n\nYES:\n\n```\npow({base: x, exponent: y, scalar: v})\n```\n\nNO:\n\n```\npow(x, y, v)\n```\n\n##### C. Prefer named parameters in mapping types.\n\nExplicit naming parameters in mapping types is helpful for clarity, especially when nesting is used.\n\nYES:\n\n```\nmapping(address account =\u003e mapping(address asset =\u003e uint256 amount)) public balances;\n```\n\nNO:\n\n```\nmapping(uint256 =\u003e mapping(address =\u003e uint256)) public balances;\n```\n\n#### 4. Structure of a Contract\n\n##### A. Prefer composition over inheritance.\n\nIf a function or set of functions could reasonably be defined as its own contract or as a part of a larger contract, prefer defining it as part of a larger contract. This makes the code easier to understand and audit.\n\nNote this _does not_ mean that we should avoid inheritance, in general. Inheritance is useful at times, most especially when building on existing, trusted contracts. For example, _do not_ reimplement `Ownable` functionality to avoid inheritance. Inherit `Ownable` from a trusted vendor, such as [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/) or [Solady](https://github.com/Vectorized/solady).\n\n##### B. Avoid writing interfaces.\n\nInterfaces separate NatSpec from contract logic, requiring readers to do more work to understand the code. For this reason, they should be avoided.\n\n##### C. Avoid using assembly.\n\nAssembly code is hard to read and audit. We should avoid it unless the gas savings are very consequential, e.g. \u003e 25%.\n\n#### 4. Versioning\n\n##### A. Avoid unnecessary version Pragma constraints.\n\nWhile the main contracts we deploy should specify a single Solidity version, all supporting contracts and libraries should have as open a Pragma as possible. A good rule of thumb is to the next major version. For example\n\n```solidity\npragma solidity ^0.8.0;\n```\n\n#### 5. Struct and Error Definitions\n\n##### A. Prefer declaring structs and errors within the interface, contract, or library where they are used.\n\n##### B. If a struct or error is used across many files, with no interface, contract, or library reasonably being the \"owner,\" then define them in their own file. Multiple structs and errors can be defined together in one file.\n\n#### 6. Imports\n\n##### A. Use named imports.\n\nNamed imports help readers understand what exactly is being used and where it is originally declared.\n\nYES:\n\n```solidity\nimport {Contract} from \"./contract.sol\"\n```\n\nNO:\n\n```solidity\nimport \"./contract.sol\"\n```\n\nFor convenience, named imports do not have to be used in test files.\n\n##### B. Order imports alphabetically (A to Z) by file name.\n\nYES:\n\n```solidity\nimport {A} from './A.sol'\nimport {B} from './B.sol'\n```\n\nNO:\n\n```solidity\nimport {B} from './B.sol'\nimport {A} from './A.sol'\n```\n\n##### C. Group imports by external and local with a new line in between.\n\nFor example\n\n```solidity\nimport {Math} from '/solady/Math.sol'\n\nimport {MyHelper} from './MyHelper.sol'\n```\n\nIn test files, imports from `/test` should be their own group, as well.\n\n```solidity\nimport {Math} from '/solady/Math.sol'\n\nimport {MyHelper} from '../src/MyHelper.sol'\n\nimport {Mock} from './mocks/Mock.sol'\n```\n\n#### 7. Comments\n\n##### A. Commenting to group sections of the code is permitted.\n\nSometimes authors and readers find it helpful to comment dividers between groups of functions. This permitted, however ensure the style guide [ordering of functions](https://docs.soliditylang.org/en/latest/style-guide.html#order-of-functions) is still followed.\n\nFor example\n\n```solidity\n/// External Functions ///\n```\n\n```solidity\n/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n/*                   VALIDATION OPERATIONS                    */\n/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n```\n\n##### B. ASCII Art\n\nASCII art is permitted in the space between the end of the Pragmas and the beginning of the imports.\n\n## 2. Development\n\n### A. Use [Forge](https://github.com/foundry-rs/foundry/tree/master/crates/forge) for testing and dependency management.\n\n### B. Testing\n\n#### 1. Test file names should follow Solidity Style Guide conventions for files names and also have `.t` before `.sol`.\n\nFor example, `ERC20.t.sol`\n\n#### 2. Test contract names should include the name of the contract or function being tested, followed by \"Test\".\n\nFor example,\n\n- `ERC20Test`\n- `TransferFromTest`\n\n#### 3. Test names should follow the convention `test_functionName_outcome_optionalContext`\n\nFor example\n\n- `test_transferFrom_debitsFromAccountBalance`\n- `test_transferFrom_debitsFromAccountBalance_whenCalledViaPermit`\n- `test_transferFrom_reverts_whenAmountExceedsBalance`\n\nIf the contract is named after a function, then function name can be omitted.\n\n```solidity\ncontract TransferFromTest {\n  function test_debitsFromAccountBalance() ...\n}\n```\n\n#### 4. Prefer tests that test one thing.\n\nThis is generally good practice, but especially so because Forge does not give line numbers on assertion failures. This makes it hard to track down what, exactly, failed if a test has many assertions.\n\nYES:\n\n```solidity\nfunction test_transferFrom_debitsFrom() {\n  ...\n}\n\nfunction test_transferFrom_creditsTo() {  \n  ...\n}\n\nfunction test_transferFrom_emitsCorrectly() {\n  ...\n}\n\nfunction test_transferFrom_reverts_whenAmountExceedsBalance() {\n  ...\n}\n```\n\nNO:\n\n```solidity\nfunction test_transferFrom_works() {\n  // debits correctly\n  // credits correctly\n  // emits correctly\n  // reverts correctly\n}\n```\n\nNote, this does not mean a test should only ever have one assertion. Sometimes having multiple assertions is helpful for certainty on what is being tested.\n\n```solidity\nfunction test_transferFrom_creditsTo() {\n  assertEq(balanceOf(to), 0);\n  ...\n  assertEq(balanceOf(to), amount);\n}\n```\n\n#### 5. Use variables for important values in tests\n\nYES:\n\n```solidity\nfunction test_transferFrom_creditsTo() {\n  assertEq(balanceOf(to), 0);\n  uint amount = 10;\n  transferFrom(from, to, amount);\n  assertEq(balanceOf(to), amount);\n}\n```\n\nNO:\n\n```solidity\nfunction test_transferFrom_creditsTo() {\n  assertEq(balanceOf(to), 0);\n  transferFrom(from, to, 10);\n  assertEq(balanceOf(to), 10);\n}\n```\n\n#### 6. Prefer fuzz tests.\n\nAll else being equal, prefer fuzz tests.\n\nYES:\n\n```solidity\nfunction test_transferFrom_creditsTo(uint amount) {\n  assertEq(balanceOf(to), 0);\n  transferFrom(from, to, amount);\n  assertEq(balanceOf(to), amount);\n}\n```\n\nNO:\n\n```solidity\nfunction test_transferFrom_creditsTo() {\n  assertEq(balanceOf(to), 0);\n  uint amount = 10;\n  transferFrom(from, to, amount);\n  assertEq(balanceOf(to), amount);\n}\n```\n\n### C. Project Setup\n\n#### 1. Avoid custom remappings.\n\n[Remappings](https://book.getfoundry.sh/projects/dependencies?#remapping-dependencies) help Forge find dependencies based on import statements. Forge will automatically deduce some remappings, for example\n\n```rust\nforge-std/=lib/forge-std/src/\nsolmate/=lib/solmate/src/\n```\n\nWe should avoid adding to these or defining any remappings explicitly, as it makes our project harder for others to use as a dependency. For example, if our project depends on Solmate and so does theirs, we want to avoid our project having some irregular import naming, resolved with a custom remapping, which will conflict with their import naming.\n\n### D. Upgradability\n\n#### 1. Prefer [ERC-7201](https://eips.ethereum.org/EIPS/eip-7201) \"Namespaced Storage Layout\" convention to avoid storage collisions.\n\n### E. Structs\n\n#### 1. Where possible, struct values should be packed to minimize SLOADs and SSTOREs.\n\n#### 2. Timestamp fields in a struct should be at least uint32 and ideally be uint40.\n\n`uint32` will give the contract ~82 years of validity `(2^32 / (60*60*24*365)) - (2024 - 1970)`. If space allows, uint40 is the preferred size.\n\n## 3. NatSpec\n\n### A. Unless an exception or addition is specifically noted, follow [Solidity NatSpec](https://docs.soliditylang.org/en/latest/natspec-format.html).\n\n### B. Additions\n\n#### 1. All external functions, events, and errors should have complete NatSpec.\n\nMinimally including `@notice`. `@param` and `@return` should be present if there are parameters or return values.\n\n#### 2. Struct NatSpec\n\nStructs can be documented with a `@notice` above and, if desired, `@dev` for each field.\n\n```solidity\n/// @notice A struct describing an accounts position\nstruct Position {\n  /// @dev The unix timestamp (seconds) of the block when the position was created.\n  uint created;\n  /// @dev The amount of ETH in the position \n  uint amount;\n}\n```\n\n#### 3. Newlines between tag types.\n\nFor easier reading, add a new line between tag types, when multiple are present and there are three or more lines.\n\nYES:\n\n```solidity\n/// @notice ...\n///\n/// @dev ...\n/// @dev ...\n/// \n/// @param ...\n/// @param ...\n/// \n/// @return\n```\n\nNO:\n\n```solidity\n/// @notice ...\n/// @dev ...\n/// @dev ...\n/// @param ...\n/// @param ...\n/// @return\n```\n\n#### 4. Author should be Coinbase.\n\nIf you using the `@author` tag, it should be\n\n```solidity\n/// @author Coinbase\n```\n\nOptionally followed by a link to the public Github repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoinbase%2Fsolidity-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoinbase%2Fsolidity-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoinbase%2Fsolidity-style-guide/lists"}