Git Product home page Git Product logo

solgrep's Introduction

get in touch with Consensys Diligence
[ ๐ŸŒ ๐Ÿ“ฉ ๐Ÿ”ฅ ]

๐Ÿง  SolGrep - A scriptable semantic grep utility for solidity

So you have a set of smart contracts and want to find all contracts that have a public method named withdrawEth but lexical grep yields a lot of false-positives? Here's where solgrep can help! ๐Ÿ™Œ

๐Ÿ’พ npm install -g solgrep

Solgrep recursively finds smart contracts in a target directory, parses the source units to understand the language semantics, and makes this information available to a powerful javascript-based filter function. This way, you can:

  • extract semantic information from solidity source code based on custom filter functions
  • find target contracts based on a custom filter script you define
  • create & run your own or built-in rules (e.g. for CI checks)
  • crunch numbers and generate statistics from a code base
  • find doppelgangers! i.e. duplicate contracts sharing the same code structure (AST_EXACT and AST_FUZZY matching)

Probably the most common way to use this tool is to run it with the --find=<js-filter-statement> option, where js-filter-statement is a javascript one-liner that tells the engine what you are interested in. You either provide a statement that returns boolean ("find mode") or return information you want to extract ("extract mode").

solgrep2

โš ๏ธ Make sure to only allow trusted inputs to --find=<js-filter-statement> as this argument is being evaluated as javascript!

โš ๏ธ Check out the proper order for arguments when using --find, --rule. See Usage.

Examples

Run the default rules and display some stats?

โ‡’  solgrep <folder> 

Run a specific or multiple built-in rules (solgrep -l to list available rules)? ๐Ÿ‘‰

โ‡’  solgrep <folder> --rule=IsInitializable --rule=Stats

You want to find all source-units with a contract that has a function named withdrawEth? ๐Ÿ‘‰

โ‡’  solgrep <folder> --find="function.name=='withdrawEth'" 

Do the same thing but case-insensitive? ๐Ÿ‘‰

โ‡’  solgrep <folder> --find="function.name.toLowerCase()=='withdraweth'" 

Find all functions that call selfdestruct? ๐Ÿ‘‰

โ‡’  solgrep <folder> --find="function.callsTo('selfdestruct')"

Exctract all function names from all contracts? ๐Ÿ‘‰

โ‡’  solgrep <folder> --find="function.name" 

Get a list of all external functions? ๐Ÿ‘‰

โ‡’  solgrep <folder> --find="function.visibility.includes('external')"  

Find ERC777 contracts? ๐Ÿ‘‰

โ‡’  solgrep <folder> --find="contract.name=='ERC777'" 

Extract all Contract names? ๐Ÿ‘‰

โ‡’  solgrep <folder> --find="contract.name"

Extract all Interface names? ๐Ÿ‘‰

โ‡’  solgrep <folder> --find="contract.name && contract.kind=='interface'"

Match against something in the AST? ๐Ÿ‘‰

โ‡’  solgrep <folder> --find="Object.keys(function.modifiers).includes('nonReentrant')"

Lexial match a functions source code? ๐Ÿ‘‰

โ‡’  solgrep <folder> --find="function.getSource().includes('hi')"

Find duplicate contracts? (AST exact and fuzzy matching) ๐Ÿ‘‰

โ‡’  solgrep <folder> --rule DupeFinder

Use option --output=<output.json> to write all results to a file.

Built-In Keywords for --find

  • The sourceUnit object matches the source-file the engine is currently processing.
  • The contract object matches the contract the engine is currently processing.
  • The function object matches the function the engine is currently processing.

Available Methos

The following methods are available:

  • <sourceUnit|contract|function>.getSource() - provides access to the units source code
  • <sourceUnit|contract|function>.ast - provides direct access to the solidity-parser AST
  • function.callsTo('withdrawEth') - find all functions in all contracts that call a method named withdrawEth
  • There's even more information easily available (functions/events/pragmas/etc.). Go check out the Solidity SourceUnit/Contract/Function Wrapper Classes functionality (attribs/functions).

Special Functions

Special contract functions can be references as:

  • function.name == '__fallback__'
  • function.name == '__receiveEther__'
  • function.name == '__constructor__'

Built-In Rules

  • Stats - collects stats about how many files, contracts, unique names, etc. were processed
  • GenericGrep - is the engine behind the --find feature
  • ...

SHARING IS CARING - submit your rules!

Usage

โ‡’  solgrep --help
Usage: solgrep <folder|...> [options]

Options:
  -r, --rule        Enable rules                           [array] [default: []]
  -l, --list-rules  List available rules              [boolean] [default: false]
  -f, --find        Find/Extract information using custom pattern
                                                           [array] [default: []]
  -o, --output      Write "results" as JSON to output file path.        [string]
  -h, --help        Show help                                          [boolean]
  -v, --version     Show version number                                [boolean]

โš ๏ธ when using multi-options (--find, --rule) make sure to use this format:

โ‡’  solgrep <folder|...> [options]

or

โ‡’  solgrep [options] -- <folder|...> 

or else additional options might be interpreted as additional --find options!

Library

const solgrep = require('solgrep');

let sg = new SolGrep('::memory::', rules, callbacks);
sg.analyzeDir("/path/to/smart/contracts").then(() => {
    console.log("   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Results")
    console.log(sg.results)
    console.log("   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")
    sgrep.close();
})

Demo

Here's an example that illustrates how to extract all function names from all sourceUnits and contracts.

โ‡’  solgrep ../d0  --find='function.name' 
๐Ÿง  SolGrep v0.0.3 ready!

  Enabled Modules:
    โœ”๏ธ GenericGrep          _function.name

[โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ] 100% | ๐Ÿ•™ ETA: 0s | 5/5 | ๐ŸŒฒ 389 | ๐Ÿ”ฅ 0 | ๐Ÿ—‚๏ธ  ../d0

   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
{
  '../d0/D0788Af7a613b81F437a51b96594A6387c7329b1_PendleLiquidityMiningBaseV2Multi.sol': [
    {
      rule: 'GenericGrep',
      tag: 'match-function: PendleLiquidityMiningBaseV2Multi.__constructor__',
      info: '__constructor__',
      loc: [Object]
    },
    {
      rule: 'GenericGrep',
      tag: 'match-function: PendleLiquidityMiningBaseV2Multi.setUpEmergencyMode',
      info: 'setUpEmergencyMode',
      loc: [Object]
    },
...

Run default Rulesets

If you provide no configuration options it will take the default built-in grep rules and crunch numbers using the stats module.

โ‡’  solgrep ../d6 
๐Ÿง  SolGrep v0.0.1 starting ...


  ๐Ÿ“ ../d6
 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 100% | ETA: 0s | 5/5

   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Results
{
  '../d6/d60a598998ed27a7C54315F2675908B628E434B1_LiquidityPool.sol': [
    {
      rule: 'IsInitializable',
      tag: 'INITIALIZEABLE',
      info: 'initialize - public initialize function; likely proxy'
    },
    {
      rule: 'IsInitializable',
      tag: 'INITIALIZEABLE',
      info: 'initialize - public initialize function; likely proxy'
    }
  ],
  '../d6/d64E77C7C6A1dcC7e302F8fe31A22745e223c39c_MyStrategy.sol': [
    {
      rule: 'IsInitializable',
      tag: 'INITIALIZEABLE',
      info: 'initialize - public initialize function; likely proxy'
    }
  ],
  undefined: [ { rule: 'Stats', tag: 'STATS', info: [Object] } ]
}
   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
{
  sourceUnits: 4,
  contracts: {
    total: 13,
    names: {
      ERC20: 1,
      StrategySushiEthMimLp: 1,
      LiquidityPool: 1,
      Getter: 1,
      Governance: 1,
      LibraryEvents: 1,
      Perpetual: 1,
      Storage: 1,
      ArbiBoneman: 1,
      ERC721: 1,
      MyStrategy: 1,
      PausableUpgradeable: 1,
      SettAccessControl: 1
    }
  },
  interfaces: {
    total: 39,
    names: {
      IERC20: 1,
      IJar: 1,
      IStakingRewards: 1,
      IStakingRewardsFactory: 1,
      IMasterchef: 1,
      UniswapRouterV2: 1,
      IUniswapV2Pair: 1,
      IUniswapV2Factory: 1,
      IRewarder: 1,
      IMiniChefV2: 1,
      ILiquidityPool: 1,
      IOracle: 1,
      IAccessControl: 1,
      IGovernor: 1,
      IPoolCreatorFull: 1,
      ISymbolService: 1,
      IPoolCreator: 1,
      ITracer: 1,
      IVersionControl: 1,
      IVariables: 1,
      IKeeperWhitelist: 1,
      IProxyAdmin: 1,
      IDecimals: 1,
      ILiquidityPoolGetter: 1,
      ILiquidityPoolGovernance: 1,
      IPerpetual: 1,
      IERC721Enumerable: 1,
      IERC721: 1,
      IERC721Receiver: 1,
      IERC721Metadata: 1,
      IERC165: 1,
      ICurveGauge: 1,
      ICurveStableSwapREN: 1,
      IUniswapRouterV2: 1,
      IStrategy: 1,
      IController: 2,
      IERC20Upgradeable: 2
    }
  },
  libraries: {
    total: 31,
    names: {
      SafeMath: 1,
      SafeERC20: 1,
      BoringERC20: 1,
      EnumerableSetUpgradeable: 1,
      SafeCastUpgradeable: 1,
      AMMModule: 1,
      LiquidityPoolModule: 1,
      PerpetualModule: 1,
      SignedSafeMathUpgradeable: 1,
      Constant: 1,
      Math: 1,
      SafeMathExt: 1,
      Utils: 1,
      MarginAccountModule: 1,
      EnumerableSet: 1,
      OrderData: 1,
      CollateralModule: 1,
      TradeModule: 1,
      OrderModule: 1,
      Signature: 1,
      ECDSAUpgradeable: 1,
      Strings: 1,
      MathUpgradeable: 1,
      Address: 2,
      SafeMathUpgradeable: 2,
      AddressUpgradeable: 2,
      SafeERC20Upgradeable: 2
    }
  },
  abstract: {
    total: 13,
    names: {
      StrategyBase: 1,
      StrategySushiFarmBase: 1,
      ReentrancyGuardUpgradeable: 1,
      ERC721Enumerable: 1,
      Ownable: 1,
      ERC165: 1,
      BaseStrategy: 1,
      Context: 2,
      ContextUpgradeable: 2,
      Initializable: 2
    }
  }
}
TOTAL FILES: 5
ERRORS: 1
   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€



cheers ๐Ÿ™Œ 
    @tintinweb 
    ConsenSys Diligence @ https://consensys.net/diligence/
    https://github.com/tintinweb/solgrep/ 

solgrep's People

Contributors

arpadatscorp avatar tintinweb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

solgrep's Issues

Exception on small source

solgrep dummy.sol --find="function.name"

gives

/usr/local/lib/node_modules/solgrep/src/rules/builtin.js:33
            return p.replaceAll(remapFunction, '_function.')
                     ^
TypeError: p.replaceAll is not a function
    at /usr/local/lib/node_modules/solgrep/src/rules/builtin.js:33:22
    at Array.map (<anonymous>)
    at GenericGrep._normalizePatterns (/usr/local/lib/node_modules/solgrep/src/rules/builtin.js:29:20)
    at new GenericGrep (/usr/local/lib/node_modules/solgrep/src/rules/builtin.js:23:30)
    at main (/usr/local/lib/node_modules/solgrep/bin/main.js:90:30)
    at Object.<anonymous> (/usr/local/lib/node_modules/solgrep/bin/main.js:161:1)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)

tested on windows/linux
SolGrep v0.0.7

installed with
sudo npm install solgrep -g

simple source
dummy.zip

stats works, but everything else fails, like --find="function.name == 'fallback'"

Speed up

It takes 2-3secs to do one query on 100lines,
and it takes multiple calls to one contract to get meaningfull info out.
So ~10secs/contract on i5, it could sure use some profiling :)

Stopping Solgrep.

Made a typo. Tried CTRL+C \ CTRL+D \ almost everything. See you in 30494seconds.

( ps -A | grep solgrep then kill )

Output groups

When doing multiple filters at the same time, can we have groups in the output?
Otherwise the output is just a continuous blob, impossible to distinguish which output belongs to which filter.
Calling the tool multiple times is less efficient.

for
solgrep --find="function.visibility.includes('external')" --find="function.name" --rule=Stats

suggested output:

{[ 
  {rule="find="function.visibility.includes('external')"",   [results] },
  {rule="find="function.name",   [results] },
  {rule="Stats",   [results] },
]}

Fails to extract

Running
solgrep --find="function.name" test.sol

on

contract ReEntrancyGuard {
    bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        selfdestruct(343434);
        locked = false;
    }
}

contract ReEntrancyGuard2 {
    bool internal locked;
}

gives no results:

๏ฟฝ SolGrep v0.0.6 ready!

  Enabled Modules:
    โœ”๏ธ GenericGrep          _function.name,test.sol

   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
cheers ๏ฟฝ
    @tintinweb
    ConsenSys Diligence @ https://consensys.net/diligence/
    https://github.com/tintinweb/solgrep/

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.