diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2e1ab882..fdae57ce 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -56,17 +56,17 @@ jobs: key: cape-v5-${{ hashFiles('Cargo.lock') }} - name: Linting - run: nix-shell --run "prepend-timestamps lint-ci" + run: nix-shell --run "lint-ci" - name: Build Slow Tests # Make sure the slow tests build, but don't run them (we have another workflow for that). - run: nix-shell --run "prepend-timestamps cargo test --release --features=slow-tests --no-run" + run: nix-shell --run "cargo test --release --features=slow-tests --no-run" - name: Run Tests - run: nix-shell --run "prepend-timestamps cape-test-geth" + run: nix-shell --run "cape-test-geth" - name: Generate Docs - run: nix-shell --run "prepend-timestamps make-doc" + run: nix-shell --run "make-doc" - name: Build all executables run: nix-shell --run "cargo build --release" diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml new file mode 100644 index 00000000..72990bcc --- /dev/null +++ b/.github/workflows/slither.yml @@ -0,0 +1,42 @@ +name: Slither + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +jobs: + slither: + runs-on: [self-hosted, X64] + container: + image: ghcr.io/espressosystems/nix:main + volumes: + - github_nix_281:/nix + steps: + - uses: styfle/cancel-workflow-action@0.9.1 + name: Cancel Outdated Builds + with: + access_token: ${{ github.token }} + + - uses: cachix/cachix-action@v10 + with: + name: espresso-systems-private + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + + - uses: actions/checkout@v2 + name: Checkout Repository + + - name: Work around git issue after git CVE-2022-24765 fix. + run: git config --global --add safe.directory "$PWD" + + - name: Run slither + run: nix-shell --run "slither ./contracts --sarif slither.sarif" + continue-on-error: true + + - name: Upload slither SARIF file + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: slither.sarif + diff --git a/.github/workflows/slow-tests.yml b/.github/workflows/slow-tests.yml index ab0148d4..c80218c8 100644 --- a/.github/workflows/slow-tests.yml +++ b/.github/workflows/slow-tests.yml @@ -29,7 +29,7 @@ jobs: - uses: cachix/cachix-action@v10 with: name: espresso-systems-private - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - name: Potential broken submodules fix run: | @@ -53,4 +53,4 @@ jobs: key: cape-v5-${{ hashFiles('Cargo.lock') }} - name: Run Tests - run: nix-shell --run "prepend-timestamps cape-test-geth-slow" + run: nix-shell --run "cape-test-geth-slow" diff --git a/.gitignore b/.gitignore index 5524ea61..949ddce4 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,6 @@ __pycache__/ .*.sw* scratch/ + +# Slither analysis results +slither.sarif diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1fbe9c9d..7849574f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,13 +16,13 @@ lint: tags: - docker script: - - nix-shell --run "prepend-timestamps lint-ci" + - nix-shell --run "lint-ci" test: tags: - docker script: - - nix-shell --run "prepend-timestamps cape-test-geth" + - nix-shell --run "cape-test-geth" cache: key: cape-test paths: @@ -33,7 +33,7 @@ doc: tags: - docker script: - - nix-shell --run "prepend-timestamps make-doc" + - nix-shell --run "make-doc" artifacts: paths: - doc diff --git a/Slither.md b/Slither.md new file mode 100644 index 00000000..e8dc7077 --- /dev/null +++ b/Slither.md @@ -0,0 +1,21 @@ + + +# Slither + +Run `run-slither` to analyze the contracts. + +To disable warnings add a code comment, for example + + // slither-disable-next-line variable-scope + +The configuration file is [slither.config.json](./slither.config.json). + +The slither github workflow file is +[.github/workflows/slither.yml](./.github/workflows/slither.yml). diff --git a/bin/prepend-timestamps b/bin/prepend-timestamps deleted file mode 100755 index 33a9d771..00000000 --- a/bin/prepend-timestamps +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2022 Espresso Systems (espressosys.com) -# This file is part of the Configurable Asset Privacy for Ethereum (CAPE) library. -# -# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# You should have received a copy of the GNU General Public License along with this program. If not, see . - -set -euo pipefail - -$@ | ts '[%Y-%m-%d %H:%M:%S]' diff --git a/bin/run-ci-tests b/bin/run-ci-tests index 8214966d..95908460 100755 --- a/bin/run-ci-tests +++ b/bin/run-ci-tests @@ -10,6 +10,7 @@ set -euo pipefail make-doc lint-ci +run-slither cape-test-geth echo Ok! diff --git a/bin/run-slither b/bin/run-slither index 6eeb4cd9..65001748 100755 --- a/bin/run-slither +++ b/bin/run-slither @@ -9,5 +9,4 @@ set -euo pipefail -slither --solc-remaps @openzeppelin/=`pwd`/node_modules/.pnpm/@openzeppelin+contracts@4.3.3/node_modules/@openzeppelin/,@rari-capital/=`pwd`/node_modules/.pnpm/@rari-capital+solmate@6.2.0/node_modules/@rari-capital/,solidity-bytes-utils/=`pwd`/node_modules/.pnpm/solidity-bytes-utils@0.8.0/node_modules/solidity_bytes_utils/ contracts - +slither contracts diff --git a/contracts/contracts.svg b/contracts/contracts.svg index 3796a8fd..15d27fbe 100644 --- a/contracts/contracts.svg +++ b/contracts/contracts.svg @@ -4,252 +4,255 @@ - - + + UmlClassDiagram - + 0 - -AssetRegistry - -Public: -   DOM_SEP_FOREIGN_ASSET: bytes13 -   DOM_SEP_DOMESTIC_ASSET: bytes14 -   CAP_NATIVE_ASSET_CODE: uint256 -   assets: mapping(bytes32=>address) - + +AssetRegistry + +Public: +   DOM_SEP_FOREIGN_ASSET: bytes13 +   DOM_SEP_DOMESTIC_ASSET: bytes14 +   CAP_NATIVE_ASSET_CODE: uint256 +   assets: mapping(bytes32=>address) + +External: +    sponsorCapeAsset(erc20Address: address, newAsset: AssetDefinition) Public:    <<event>> AssetSponsored(erc20Address: address, assetDefinitionCode: uint256)    nativeDomesticAsset(): (assetDefinition: AssetDefinition)    lookup(assetDefinition: AssetDefinition): address    isCapeAssetRegistered(assetDefinition: AssetDefinition): bool -    sponsorCapeAsset(erc20Address: address, newAsset: AssetDefinition) 7 - -<<Library>> -BN254 - -Public: -   P_MOD: uint256 -   R_MOD: uint256 - - + +<<Library>> +BN254 + +Public: +   P_MOD: uint256 +   R_MOD: uint256 + + 0->7 - - + + 8 - -<<Library>> -EdOnBN254 - -Public: -   P_MOD: uint256 - - + +<<Library>> +EdOnBN254 + +Public: +   P_MOD: uint256 + + 0->8 - - + + 0struct0 - -<<struct>> -AssetDefinition - -code: uint256 -policy: AssetPolicy + +<<struct>> +AssetDefinition + +code: uint256 +policy: AssetPolicy 0struct0->0 - - + + 0struct1 - -<<struct>> -AssetPolicy - -auditorPk: EdOnBN254.EdOnBN254Point -credPk: EdOnBN254.EdOnBN254Point -freezerPk: EdOnBN254.EdOnBN254Point -revealMap: uint256 -revealThreshold: uint128 + +<<struct>> +AssetPolicy + +auditorPk: EdOnBN254.EdOnBN254Point +credPk: EdOnBN254.EdOnBN254Point +freezerPk: EdOnBN254.EdOnBN254Point +revealMap: uint256 +revealThreshold: uint128 0struct1->0 - - + + 1 - -CAPE - -Public: -   nullifiers: mapping(uint256=>bool) -   blockHeight: uint64 -   pendingDeposits: uint256[] -   deployer: address -   faucetInitialized: bool -   CAPE_BURN_MAGIC_BYTES: bytes -   CAPE_BURN_MAGIC_BYTES_SIZE: uint256 -   MAX_NUM_PENDING_DEPOSIT: uint256 - -Public: -    <<event>> FaucetInitialized(roBytes: bytes) -    <<event>> BlockCommitted(height: uint64, depositCommitments: uint256[], minerAddr: bytes, noteTypes: bytes, transferNotes: bytes, mintNotes: bytes, freezeNotes: bytes, burnNotes: bytes) -    <<event>> Erc20TokensDeposited(roBytes: bytes, erc20TokenAddress: address, from: address) -    constructor(nRoots: uint64, verifierAddr: address, recordsMerkleTreeAddr: address) -    faucetSetupForTestnet(faucetManagerAddress: EdOnBN254.EdOnBN254Point, faucetManagerEncKey: bytes32) -    depositErc20(ro: RecordOpening, erc20Address: address) -    submitCapeBlockWithMemos(newBlock: CapeBlock, extraData: bytes) -    submitCapeBlock(newBlock: CapeBlock) -    getRootValue(): uint256 + +CAPE + +Public: +   nullifiers: mapping(uint256=>bool) +   blockHeight: uint64 +   pendingDeposits: uint256[] +   deployer: address +   faucetInitialized: bool +   CAPE_BURN_MAGIC_BYTES: bytes +   CAPE_BURN_MAGIC_BYTES_SIZE: uint256 +   MAX_NUM_PENDING_DEPOSIT: uint256 + +External: +    faucetSetupForTestnet(faucetManagerAddress: EdOnBN254.EdOnBN254Point, faucetManagerEncKey: bytes32) +    depositErc20(ro: RecordOpening, erc20Address: address) +    submitCapeBlockWithMemos(newBlock: CapeBlock, bytes) +    getRootValue(): uint256 +Public: +    <<event>> FaucetInitialized(roBytes: bytes) +    <<event>> BlockCommitted(height: uint64, depositCommitments: uint256[], minerAddr: bytes, noteTypes: bytes, transferNotes: bytes, mintNotes: bytes, freezeNotes: bytes, burnNotes: bytes) +    <<event>> Erc20TokensDeposited(roBytes: bytes, erc20TokenAddress: address, from: address) +    constructor(nRoots: uint64, verifierAddr: address, recordsMerkleTreeAddr: address) +    submitCapeBlock(newBlock: CapeBlock) 1->0 - - + + 3 - -RootStore - - - -Public: -    constructor(nRoots: uint64) + +RootStore + + + +Public: +    constructor(nRoots: uint64) 1->3 - - + + 4 - -<<Interface>> -IPlonkVerifier - - - -External: -     batchVerify(verifyingKeys: VerifyingKey[], publicInputs: uint256[][], proofs: PlonkProof[], extraTranscriptInitMsgs: bytes[]): bool + +<<Interface>> +IPlonkVerifier + + + +External: +     batchVerify(verifyingKeys: VerifyingKey[], publicInputs: uint256[][], proofs: PlonkProof[], extraTranscriptInitMsgs: bytes[]): bool 1->4 - - + + 5 - -<<Interface>> -IRecordsMerkleTree - - - -External: -     updateRecordsMerkleTree(elements: uint256[]) -     getRootValue(): uint256 -     getHeight(): uint8 -     getNumLeaves(): uint64 + +<<Interface>> +IRecordsMerkleTree + + + +External: +     updateRecordsMerkleTree(elements: uint256[]) +     getRootValue(): uint256 +     getHeight(): uint8 +     getNumLeaves(): uint64 1->5 - - + + 6 - -<<Library>> -AccumulatingArray - - - - + +<<Library>> +AccumulatingArray + + + + 1->6 - - + + 1->8 - - + + 13 - -<<Library>> -RescueLib - - - + +<<Library>> +RescueLib + + + +External: +    commit(inputs: uint256[]): uint256 Public:    hash(a: uint256, b: uint256, c: uint256): (o: uint256) -    commit(inputs: uint256[]): uint256 1->13 - - + + 19 - -<<Library>> -VerifyingKeys - - - -External: -    getVkById(encodedId: uint256): IPlonkVerifier.VerifyingKey -Public: -    getEncodedId(noteType: uint8, numInput: uint8, numOutput: uint8, treeDepth: uint8): (encodedId: uint256) + +<<Library>> +VerifyingKeys + + + +External: +    getVkById(encodedId: uint256): IPlonkVerifier.VerifyingKey +Public: +    getEncodedId(noteType: uint8, numInput: uint8, numOutput: uint8, treeDepth: uint8): (encodedId: uint256) 1->19 - - + + @@ -264,8 +267,8 @@ 1struct0->1 - - + + @@ -283,8 +286,8 @@ 1struct1->1 - - + + @@ -299,8 +302,8 @@ 1struct2->1 - - + + @@ -322,8 +325,8 @@ 1struct3->1 - - + + @@ -340,8 +343,8 @@ 1struct4->1 - - + + @@ -359,8 +362,8 @@ 1struct5->1 - - + + @@ -376,8 +379,8 @@ 1struct6->1 - - + + @@ -393,8 +396,8 @@ 1struct7->1 - - + + @@ -413,8 +416,8 @@ 1struct8->1 - - + + @@ -433,8 +436,8 @@ 1struct9->1 - - + + @@ -451,30 +454,30 @@ 1enum0->1 - - + + 2 - -RecordsMerkleTree - - - -External: -    updateRecordsMerkleTree(elements: uint256[]) -Public: -    constructor(merkleTreeHeight: uint8) -    getRootValue(): uint256 -    getHeight(): uint8 -    getNumLeaves(): uint64 + +RecordsMerkleTree + + + +External: +    updateRecordsMerkleTree(elements: uint256[]) +    getRootValue(): uint256 +    getHeight(): uint8 +    getNumLeaves(): uint64 +Public: +    constructor(merkleTreeHeight: uint8) 2->13 - - + + @@ -491,8 +494,8 @@ 2struct0->2 - - + + @@ -508,482 +511,482 @@ 2enum0->2 - - + + 4->7 - - + + 4struct0 - -<<struct>> -PlonkProof - -wire0: BN254.G1Point -wire1: BN254.G1Point -wire2: BN254.G1Point -wire3: BN254.G1Point -wire4: BN254.G1Point -prodPerm: BN254.G1Point -split0: BN254.G1Point -split1: BN254.G1Point -split2: BN254.G1Point -split3: BN254.G1Point -split4: BN254.G1Point -zeta: BN254.G1Point -zetaOmega: BN254.G1Point -wireEval0: uint256 -wireEval1: uint256 -wireEval2: uint256 -wireEval3: uint256 -wireEval4: uint256 -sigmaEval0: uint256 -sigmaEval1: uint256 -sigmaEval2: uint256 -sigmaEval3: uint256 -prodPermZetaOmegaEval: uint256 + +<<struct>> +PlonkProof + +wire0: BN254.G1Point +wire1: BN254.G1Point +wire2: BN254.G1Point +wire3: BN254.G1Point +wire4: BN254.G1Point +prodPerm: BN254.G1Point +split0: BN254.G1Point +split1: BN254.G1Point +split2: BN254.G1Point +split3: BN254.G1Point +split4: BN254.G1Point +zeta: BN254.G1Point +zetaOmega: BN254.G1Point +wireEval0: uint256 +wireEval1: uint256 +wireEval2: uint256 +wireEval3: uint256 +wireEval4: uint256 +sigmaEval0: uint256 +sigmaEval1: uint256 +sigmaEval2: uint256 +sigmaEval3: uint256 +prodPermZetaOmegaEval: uint256 4struct0->4 - - + + 4struct1 - -<<struct>> -VerifyingKey - -domainSize: uint256 -numInputs: uint256 -sigma0: BN254.G1Point -sigma1: BN254.G1Point -sigma2: BN254.G1Point -sigma3: BN254.G1Point -sigma4: BN254.G1Point -q1: BN254.G1Point -q2: BN254.G1Point -q3: BN254.G1Point -q4: BN254.G1Point -qM12: BN254.G1Point -qM34: BN254.G1Point -qO: BN254.G1Point -qC: BN254.G1Point -qH1: BN254.G1Point -qH2: BN254.G1Point -qH3: BN254.G1Point -qH4: BN254.G1Point -qEcc: BN254.G1Point + +<<struct>> +VerifyingKey + +domainSize: uint256 +numInputs: uint256 +sigma0: BN254.G1Point +sigma1: BN254.G1Point +sigma2: BN254.G1Point +sigma3: BN254.G1Point +sigma4: BN254.G1Point +q1: BN254.G1Point +q2: BN254.G1Point +q3: BN254.G1Point +q4: BN254.G1Point +qM12: BN254.G1Point +qM34: BN254.G1Point +qO: BN254.G1Point +qC: BN254.G1Point +qH1: BN254.G1Point +qH2: BN254.G1Point +qH3: BN254.G1Point +qH4: BN254.G1Point +qEcc: BN254.G1Point 4struct1->4 - - + + 6struct0 - -<<struct>> -Data - -items: uint256[] -index: uint256 + +<<struct>> +Data + +items: uint256[] +index: uint256 6struct0->6 - - + + 18 - -<<Library>> -Utils - - - - + +<<Library>> +Utils + + + + 7->18 - - + + 7struct0 - -<<struct>> -G1Point - -x: uint256 -y: uint256 + +<<struct>> +G1Point + +x: uint256 +y: uint256 7struct0->7 - - + + 7struct1 - -<<struct>> -G2Point - -x0: uint256 -x1: uint256 -y0: uint256 -y1: uint256 + +<<struct>> +G2Point + +x0: uint256 +x1: uint256 +y0: uint256 +y1: uint256 7struct1->7 - - + + 8->8 - - + + 8->18 - - + + 8struct0 - -<<struct>> -EdOnBN254Point - -x: uint256 -y: uint256 + +<<struct>> +EdOnBN254Point + +x: uint256 +y: uint256 8struct0->8 - - + + 9 - -<<Library>> -Freeze2In2Out24DepthVk - - - - + +<<Library>> +Freeze2In2Out24DepthVk + + + + 9->4 - - + + 10 - -<<Library>> -Freeze3In3Out24DepthVk - - - - + +<<Library>> +Freeze3In3Out24DepthVk + + + + 10->4 - - + + 11 - -<<Library>> -Mint1In2Out24DepthVk - - - - + +<<Library>> +Mint1In2Out24DepthVk + + + + 11->4 - - + + 12 - -<<Library>> -PolynomialEval - - - - + +<<Library>> +PolynomialEval + + + + 12->7 - - + + 12struct0 - -<<struct>> -EvalDomain - -logSize: uint256 -size: uint256 -sizeInv: uint256 -groupGen: uint256 -groupGenInv: uint256 + +<<struct>> +EvalDomain + +logSize: uint256 +size: uint256 +sizeInv: uint256 +groupGen: uint256 +groupGenInv: uint256 12struct0->12 - - + + 12struct1 - -<<struct>> -EvalData - -vanishEval: uint256 -lagrangeOne: uint256 -piEval: uint256 + +<<struct>> +EvalData + +vanishEval: uint256 +lagrangeOne: uint256 +piEval: uint256 12struct1->12 - - + + 14 - -<<Library>> -Transfer1In2Out24DepthVk - - - - + +<<Library>> +Transfer1In2Out24DepthVk + + + + 14->4 - - + + 15 - -<<Library>> -Transfer2In2Out24DepthVk - - - - + +<<Library>> +Transfer2In2Out24DepthVk + + + + 15->4 - - + + 16 - -<<Library>> -Transfer2In3Out24DepthVk - - - - + +<<Library>> +Transfer2In3Out24DepthVk + + + + 16->4 - - + + 17 - -<<Library>> -Transfer3In3Out24DepthVk - - - - + +<<Library>> +Transfer3In3Out24DepthVk + + + + 17->4 - - + + 19->4 - - + + 19->14 - - + + 20 - -PlonkVerifier - - - -External: -    batchVerify(verifyingKeys: VerifyingKey[], publicInputs: uint256[][], proofs: PlonkProof[], extraTranscriptInitMsgs: bytes[]): bool + +PlonkVerifier + + + +External: +    batchVerify(verifyingKeys: VerifyingKey[], publicInputs: uint256[][], proofs: PlonkProof[], extraTranscriptInitMsgs: bytes[]): bool 20->4 - - + + 20->7 - - + + 21 - -<<Library>> -Transcript - - - - + +<<Library>> +Transcript + + + + 20->21 - - + + 20struct0 - -<<struct>> -PcsInfo - -u: uint256 -evalPoint: uint256 -nextEvalPoint: uint256 -eval: uint256 -commScalars: uint256[] -commBases: BN254.G1Point[] -openingProof: BN254.G1Point -shiftedOpeningProof: BN254.G1Point + +<<struct>> +PcsInfo + +u: uint256 +evalPoint: uint256 +nextEvalPoint: uint256 +eval: uint256 +commScalars: uint256[] +commBases: BN254.G1Point[] +openingProof: BN254.G1Point +shiftedOpeningProof: BN254.G1Point 20struct0->20 - - + + 20struct1 - -<<struct>> -Challenges - -alpha: uint256 -alpha2: uint256 -alpha3: uint256 -beta: uint256 -gamma: uint256 -zeta: uint256 -v: uint256 -u: uint256 + +<<struct>> +Challenges + +alpha: uint256 +alpha2: uint256 +alpha3: uint256 +beta: uint256 +gamma: uint256 +zeta: uint256 +v: uint256 +u: uint256 20struct1->20 - - + + 21->4 - - + + 21->7 - - + + 21->18 - - + + 21struct0 - -<<struct>> -TranscriptData - -transcript: bytes -state: bytes32[] + +<<struct>> +TranscriptData + +transcript: bytes +state: bytes32[] 21struct0->21 - - + + diff --git a/contracts/contracts/AssetRegistry.sol b/contracts/contracts/AssetRegistry.sol index 6717d523..cb29fabd 100644 --- a/contracts/contracts/AssetRegistry.sol +++ b/contracts/contracts/AssetRegistry.sol @@ -68,7 +68,7 @@ contract AssetRegistry { /// registered or the ERC-20 token address is zero. /// @param erc20Address An ERC-20 token address /// @param newAsset An asset type to be registered in the contract - function sponsorCapeAsset(address erc20Address, AssetDefinition memory newAsset) public { + function sponsorCapeAsset(address erc20Address, AssetDefinition memory newAsset) external { require(erc20Address != address(0), "Bad asset address"); require(!isCapeAssetRegistered(newAsset), "Asset already registered"); diff --git a/contracts/contracts/CAPE.sol b/contracts/contracts/CAPE.sol index e8eff92a..6bb2dacc 100644 --- a/contracts/contracts/CAPE.sol +++ b/contracts/contracts/CAPE.sol @@ -13,8 +13,6 @@ pragma solidity ^0.8.0; /// CAPE provides auditable anonymous payments on Ethereum. /// @author Espresso Systems -import "hardhat/console.sol"; - import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@rari-capital/solmate/src/utils/SafeTransferLib.sol"; @@ -180,7 +178,7 @@ contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { function faucetSetupForTestnet( EdOnBN254.EdOnBN254Point memory faucetManagerAddress, bytes32 faucetManagerEncKey - ) public { + ) external { // faucet can only be set up once by the manager require(msg.sender == deployer, "Only invocable by deployer"); require(!faucetInitialized, "Faucet already set up"); @@ -198,10 +196,15 @@ contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { uint256[] memory recordCommitments = new uint256[](1); recordCommitments[0] = _deriveRecordCommitment(ro); - // insert the record into record accumulator + // Insert the record into record accumulator. + // + // This is a call to our own contract, not an arbitrary external contract. + // slither-disable-next-line reentrancy-no-eth _recordsMerkleTree.updateRecordsMerkleTree(recordCommitments); + // slither-disable-next-line reentrancy-benign _addRoot(_recordsMerkleTree.getRootValue()); + // slither-disable-next-line reentrancy-events emit FaucetInitialized(abi.encode(ro)); faucetInitialized = true; } @@ -227,7 +230,7 @@ contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { /// @notice Wraps ERC-20 tokens into a CAPE asset defined in the record opening. /// @param ro record opening that will be inserted in the records merkle tree once the deposit is validated /// @param erc20Address address of the ERC-20 token corresponding to the deposit - function depositErc20(RecordOpening memory ro, address erc20Address) public nonReentrant { + function depositErc20(RecordOpening memory ro, address erc20Address) external nonReentrant { require(isCapeAssetRegistered(ro.assetDef), "Asset definition not registered"); require(lookup(ro.assetDef) == erc20Address, "Wrong ERC20 address"); @@ -249,9 +252,11 @@ contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { /// @notice Submit a new block with extra data to the CAPE contract. /// @param newBlock block to be processed by the CAPE contract - /// @param extraData extra data to be stored in calldata; this data is ignored by the contract function - // solhint-disable-next-line no-unused-vars - function submitCapeBlockWithMemos(CapeBlock memory newBlock, bytes calldata extraData) public { + /// @param {bytes} extraData data to be stored in calldata; this data is ignored by the contract function + function submitCapeBlockWithMemos( + CapeBlock memory newBlock, + bytes calldata /* extraData */ + ) external { submitCapeBlock(newBlock); } @@ -365,7 +370,10 @@ contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { // Only update the merkle tree and add the root if the list of records commitments is non empty if (!commitments.isEmpty()) { + // This is a call to our own contract, not an arbitrary external contract. + // slither-disable-next-line reentrancy-no-eth _recordsMerkleTree.updateRecordsMerkleTree(commitments.items); + // slither-disable-next-line reentrancy-benign _addRoot(_recordsMerkleTree.getRootValue()); } @@ -373,6 +381,7 @@ contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { blockHeight += 1; // Inform clients about the new block and the processed deposits. + // slither-disable-next-line reentrancy-events _emitBlockEvent(newBlock); // Empty the queue now that the record commitments have been inserted @@ -519,6 +528,7 @@ contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { ) { // load the correct (hardcoded) vk + // slither-disable-next-line calls-loop vk = VerifyingKeys.getVkById( VerifyingKeys.getEncodedId( uint8(NoteType.TRANSFER), @@ -600,6 +610,7 @@ contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { ) { // load the correct (hardcoded) vk + // slither-disable-next-line calls-loop vk = VerifyingKeys.getVkById( VerifyingKeys.getEncodedId( uint8(NoteType.MINT), @@ -661,6 +672,7 @@ contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { ) { // load the correct (hardcoded) vk + // slither-disable-next-line calls-loop vk = VerifyingKeys.getVkById( VerifyingKeys.getEncodedId( uint8(NoteType.FREEZE), @@ -696,7 +708,7 @@ contract CAPE is RootStore, AssetRegistry, ReentrancyGuard { transcriptInitMsg = EdOnBN254.serialize(note.auxInfo.txnMemoVerKey); } - function getRootValue() public view returns (uint256) { + function getRootValue() external view returns (uint256) { return _recordsMerkleTree.getRootValue(); } } diff --git a/contracts/contracts/Greeter.sol b/contracts/contracts/Greeter.sol deleted file mode 100644 index a5ecd5cd..00000000 --- a/contracts/contracts/Greeter.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// -// Copyright (c) 2022 Espresso Systems (espressosys.com) -// This file is part of the Configurable Asset Privacy for Ethereum (CAPE) library. -// -// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// You should have received a copy of the GNU General Public License along with this program. If not, see . - -pragma solidity ^0.8.0; - -import "hardhat/console.sol"; - -contract Greeter { - string private _greeting; - - constructor(string memory greeting) { - console.log("Deploying a Greeter with _greeting:", greeting); - _greeting = greeting; - } - - function greet() public view returns (string memory) { - return _greeting; - } - - function setGreeting(string memory greeting) public { - console.log("Changing _greeting from '%s' to '%s'", _greeting, greeting); - _greeting = greeting; - } -} diff --git a/contracts/contracts/RecordsMerkleTree.sol b/contracts/contracts/RecordsMerkleTree.sol index bca6628a..cfbee729 100644 --- a/contracts/contracts/RecordsMerkleTree.sol +++ b/contracts/contracts/RecordsMerkleTree.sol @@ -9,7 +9,6 @@ pragma solidity ^0.8.0; -import "hardhat/console.sol"; import "./libraries/RescueLib.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; @@ -51,13 +50,6 @@ contract RecordsMerkleTree is Ownable { return (node.left == 0) && (node.middle == 0) && (node.right == 0); } - /// @dev Does the given node have children? - /// @param node A node - /// @return _ True if the node has at least one child, false otherwise - function _hasChildren(Node memory node) private pure returns (bool) { - return !_isTerminal(node); - } - /// @dev Is the given node null? /// @param node A node /// @return _ True if the node is NULL, false otherwise @@ -81,16 +73,15 @@ contract RecordsMerkleTree is Ownable { // indexFirstSibling = cursor - 2; // indexSecondSibling = cursor - 1; - Node memory node; if (posSibling == Position.LEFT) { - node = Node(0, cursor - 3, cursor - 2, cursor - 1); + return Node(0, cursor - 3, cursor - 2, cursor - 1); } else if (posSibling == Position.MIDDLE) { - node = Node(0, cursor - 2, cursor - 3, cursor - 1); + return Node(0, cursor - 2, cursor - 3, cursor - 1); } else if (posSibling == Position.RIGHT) { - node = Node(0, cursor - 2, cursor - 1, cursor - 3); + return Node(0, cursor - 2, cursor - 1, cursor - 3); + } else { + revert("unreachable"); } - - return node; } /// @dev Create a Merkle tree from the given frontier. @@ -155,17 +146,15 @@ contract RecordsMerkleTree is Ownable { uint64 nodeIndex, Position pos ) private pure returns (uint64) { - uint64 res; - if (pos == Position.LEFT) { - res = nodes[nodeIndex].left; + return nodes[nodeIndex].left; } else if (pos == Position.MIDDLE) { - res = nodes[nodeIndex].middle; + return nodes[nodeIndex].middle; } else if (pos == Position.RIGHT) { - res = nodes[nodeIndex].right; + return nodes[nodeIndex].right; + } else { + revert("unreachable"); } - - return res; } /// @dev Update the child of a node based on the position (which child to select) and an index to the new child. @@ -265,6 +254,14 @@ contract RecordsMerkleTree is Ownable { _updateChildNode(nodes[previousNodeIndex], newNodeIndex, Position(localPos)); // Increment the number of leaves + // + // This operation is costly and happens in a loop. However, for now the + // merkle tree is usually updated with a single new element. In this + // case we would not save gas by moving the update of _numLeaves. The + // gas cost is also likely negligible compared to the whole operation of + // inserting an element. + // + // slither-disable-next-line costly-loop _numLeaves += 1; // Return the new value of maxIndex @@ -334,17 +331,17 @@ contract RecordsMerkleTree is Ownable { } /// @notice Returns the root value of the Merkle tree. - function getRootValue() public view returns (uint256) { + function getRootValue() external view returns (uint256) { return _rootValue; } /// @notice Returns the height of the Merkle tree. - function getHeight() public view returns (uint8) { + function getHeight() external view returns (uint8) { return _merkleTreeHeight; } /// @notice Returns the number of leaves of the Merkle tree. - function getNumLeaves() public view returns (uint64) { + function getNumLeaves() external view returns (uint64) { return _numLeaves; } diff --git a/contracts/contracts/RescueNonOptimized.sol b/contracts/contracts/RescueNonOptimized.sol index f3bb6b21..b8d0539a 100644 --- a/contracts/contracts/RescueNonOptimized.sol +++ b/contracts/contracts/RescueNonOptimized.sol @@ -293,7 +293,7 @@ contract RescueNonOptimized { uint256 a, uint256 b, uint256 c - ) public returns (uint256) { + ) public view returns (uint256) { uint256[_STATE_SIZE] memory input; uint256[_STATE_SIZE] memory state; @@ -307,7 +307,7 @@ contract RescueNonOptimized { return state[0]; } - function commit(uint256[15] memory inputs) public returns (uint256) { + function commit(uint256[15] memory inputs) public view returns (uint256) { uint256 a = inputs[0]; uint256 b = inputs[1]; uint256 c = inputs[2]; diff --git a/contracts/contracts/libraries/BN254.sol b/contracts/contracts/libraries/BN254.sol index 52a7f74c..b4902ac3 100644 --- a/contracts/contracts/libraries/BN254.sol +++ b/contracts/contracts/libraries/BN254.sol @@ -284,7 +284,7 @@ library BN254 { } function g1Serialize(G1Point memory point) internal pure returns (bytes memory) { - uint256 mask; + uint256 mask = 0; // Set the 254-th bit to 1 for infinity // https://docs.rs/ark-serialize/0.3.0/src/ark_serialize/flags.rs.html#117 diff --git a/contracts/contracts/libraries/EdOnBN254.sol b/contracts/contracts/libraries/EdOnBN254.sol index 56c343dd..539ada7a 100644 --- a/contracts/contracts/libraries/EdOnBN254.sol +++ b/contracts/contracts/libraries/EdOnBN254.sol @@ -23,25 +23,13 @@ library EdOnBN254 { uint256 y; } - /// @dev check if a G1 point is Infinity - /// @notice precompile bn256Add at address(6) takes (0, 0) as Point of Infinity, - /// some crypto libraries (such as arkwork) uses a boolean flag to mark PoI, and - /// just use (0, 1) as affine coordinates (not on curve) to represents PoI. - function isInfinity(EdOnBN254Point memory point) internal pure returns (bool result) { - assembly { - let x := mload(point) - let y := mload(add(point, 0x20)) - result := and(iszero(x), iszero(y)) - } - } - /// @dev Check if y-coordinate of G1 point is negative. function isYNegative(EdOnBN254Point memory point) internal pure returns (bool) { return (point.y << 1) < P_MOD; } function serialize(EdOnBN254Point memory point) internal pure returns (bytes memory res) { - uint256 mask; + uint256 mask = 0; // Edward curve does not have an infinity flag. // Set the 255-th bit to 1 for positive Y // See: https://github.com/arkworks-rs/algebra/blob/d6365c3a0724e5d71322fe19cbdb30f979b064c8/serialize/src/flags.rs#L148 diff --git a/contracts/contracts/libraries/RescueLib.sol b/contracts/contracts/libraries/RescueLib.sol index dfefd567..1b7ec903 100644 --- a/contracts/contracts/libraries/RescueLib.sol +++ b/contracts/contracts/libraries/RescueLib.sol @@ -13,18 +13,17 @@ library RescueLib { /// The constants are obtained from the Sage script /// https://github.com/EspressoSystems/Marvellous/blob/fcd4c41672f485ac2f62526bc87a16789d4d0459/rescue254.sage - uint256 private constant _N_ROUNDS = 12; - uint256 private constant _STATE_SIZE = 4; - uint256 private constant _SCHEDULED_KEY_SIZE = (2 * _N_ROUNDS + 1) * _STATE_SIZE; + // These constants are no longer used, left here for readability. + // uint256 private constant _N_ROUNDS = 12; + // uint256 private constant _STATE_SIZE = 4; + // uint256 private constant _SCHEDULED_KEY_SIZE = (2 * _N_ROUNDS + 1) * _STATE_SIZE; + // uint256 private constant _ALPHA = 5; // Obtained by running KeyScheduling([0,0,0,0]). See Algorithm 2 of AT specification document. - // solhint-disable-next-line var-name-mixedcase uint256 private constant _PRIME = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint256 private constant _ALPHA = 5; - uint256 private constant _ALPHA_INV = 17510594297471420177797124596205820070838691520332827474958563349260646796493; @@ -155,9 +154,13 @@ library RescueLib { // @param input input for the permutation // @return permutation output function perm( + // slither-disable-next-line write-after-write uint256 s0, + // slither-disable-next-line write-after-write uint256 s1, + // slither-disable-next-line write-after-write uint256 s2, + // slither-disable-next-line write-after-write uint256 s3 ) internal @@ -169,6 +172,7 @@ library RescueLib { uint256 ) { + // slither-disable-next-line uninitialized-local uint256[6] memory alphaInvScratch; _expAlphaInv4Setup(alphaInvScratch); @@ -709,9 +713,10 @@ library RescueLib { } } - // Must be public so it doesn't get inlined into CAPE.sol and blow - // the size limit - function commit(uint256[15] memory inputs) public view returns (uint256) { + // This function is external to ensure that the solidity compiler generates + // a separate library contract. This is required to reduce the size of the + // CAPE contract. + function commit(uint256[15] memory inputs) external view returns (uint256) { checkBounded(inputs); uint256 a; diff --git a/contracts/contracts/mocks/TestRescue.sol b/contracts/contracts/mocks/TestRescue.sol index 79d98921..71297642 100644 --- a/contracts/contracts/mocks/TestRescue.sol +++ b/contracts/contracts/mocks/TestRescue.sol @@ -19,11 +19,11 @@ contract TestRescue { uint256 a, uint256 b, uint256 c - ) public returns (uint256) { + ) public view returns (uint256) { return RescueLib.hash(a, b, c); } - function commit(uint256[15] memory inputs) public returns (uint256) { + function commit(uint256[15] memory inputs) public view returns (uint256) { return RescueLib.commit(inputs); } } diff --git a/contracts/contracts/verifier/PlonkVerifier.sol b/contracts/contracts/verifier/PlonkVerifier.sol index 5078509d..d1a18302 100644 --- a/contracts/contracts/verifier/PlonkVerifier.sol +++ b/contracts/contracts/verifier/PlonkVerifier.sol @@ -10,7 +10,6 @@ pragma solidity ^0.8.0; import {BN254} from "../libraries/BN254.sol"; -import "hardhat/console.sol"; import "../interfaces/IPlonkVerifier.sol"; import {PolynomialEval as Poly} from "../libraries/PolynomialEval.sol"; import "./Transcript.sol"; @@ -212,6 +211,7 @@ contract PlonkVerifier is IPlonkVerifier { transcript.appendGroupElement(proof.wire4); // have to compute tau, but not really used anywhere + // slither-disable-next-line unused-return transcript.getAndAppendChallenge(); res.beta = transcript.getAndAppendChallenge(); res.gamma = transcript.getAndAppendChallenge(); @@ -468,6 +468,7 @@ contract PlonkVerifier is IPlonkVerifier { bases[2 * i] = pcsInfos[i].openingProof; { + // slither-disable-next-line write-after-write uint256 tmp; uint256 u = pcsInfos[i].u; assembly { @@ -505,6 +506,7 @@ contract PlonkVerifier is IPlonkVerifier { uint256 s = pcsInfos[i].commScalars[j]; uint256 tmp; assembly { + // slither-disable-next-line variable-scope tmp := mulmod(rBase, s, p) } scalars[idx] = tmp; @@ -518,6 +520,7 @@ contract PlonkVerifier is IPlonkVerifier { uint256 evalPoint = pcsInfos[i].evalPoint; uint256 tmp; assembly { + // slither-disable-next-line variable-scope tmp := mulmod(rBase, evalPoint, p) } scalars[idx] = tmp; @@ -531,6 +534,7 @@ contract PlonkVerifier is IPlonkVerifier { uint256 nextEvalPoint = pcsInfos[i].nextEvalPoint; uint256 tmp; assembly { + // slither-disable-next-line variable-scope tmp := mulmod(rBase, mulmod(u, nextEvalPoint, p), p) } scalars[idx] = tmp; diff --git a/contracts/contracts/verifier/Transcript.sol b/contracts/contracts/verifier/Transcript.sol index 393dbe56..d3387fbe 100644 --- a/contracts/contracts/verifier/Transcript.sol +++ b/contracts/contracts/verifier/Transcript.sol @@ -10,7 +10,6 @@ pragma solidity ^0.8.0; import "solidity-bytes-utils/contracts/BytesLib.sol"; -import "hardhat/console.sol"; import "../libraries/Utils.sol"; import {BN254} from "../libraries/BN254.sol"; import {IPlonkVerifier} from "../interfaces/IPlonkVerifier.sol"; diff --git a/contracts/rust/src/types.rs b/contracts/rust/src/types.rs index b1cc6080..47c5d22e 100644 --- a/contracts/rust/src/types.rs +++ b/contracts/rust/src/types.rs @@ -28,11 +28,11 @@ use std::convert::TryInto; pub use crate::bindings::{ cape_mod::BlockCommittedFilter, AssetDefinition, AssetPolicy, AssetRegistry, AuditMemo, BurnNote, CAPEEvents, CapeBlock, Challenges, EdOnBN254Point, EvalData, EvalDomain, - FreezeAuxInfo, FreezeNote, G1Point, G2Point, Greeter, MaliciousToken, MintAuxInfo, MintNote, - PcsInfo, PlonkProof, RecordOpening, RecordsMerkleTree, SimpleToken, TestBN254, TestCAPE, - TestCAPEEvents, TestCapeTypes, TestEdOnBN254, TestPlonkVerifier, TestPolynomialEval, - TestRescue, TestRootStore, TestTranscript, TestVerifyingKeys, TranscriptData, TransferAuxInfo, - TransferNote, VerifyingKey, CAPE, ERC20, + FreezeAuxInfo, FreezeNote, G1Point, G2Point, MaliciousToken, MintAuxInfo, MintNote, PcsInfo, + PlonkProof, RecordOpening, RecordsMerkleTree, SimpleToken, TestBN254, TestCAPE, TestCAPEEvents, + TestCapeTypes, TestEdOnBN254, TestPlonkVerifier, TestPolynomialEval, TestRescue, TestRootStore, + TestTranscript, TestVerifyingKeys, TranscriptData, TransferAuxInfo, TransferNote, VerifyingKey, + CAPE, ERC20, }; // The number of input wires of TurboPlonk. diff --git a/contracts/test/benchmarks/test-rescue.js b/contracts/test/benchmarks/test-rescue.js index 05b3506c..6a66da8f 100644 --- a/contracts/test/benchmarks/test-rescue.js +++ b/contracts/test/benchmarks/test-rescue.js @@ -11,7 +11,9 @@ const { ethers } = require("hardhat"); describe("Rescue benchmarks", function () { describe("Gas spent for computing the Rescue function", function () { for (const contractName of ["TestRescue", "TestRescueNonOptimized"]) { - it(`checks gas usage of ${contractName}.hash`, async function () { + let rescueContract; + + beforeEach(async function () { const libraries = {}; if (contractName == "TestRescue") { let rescueLib = await (await ethers.getContractFactory("RescueLib")).deploy(); @@ -19,74 +21,48 @@ describe("Rescue benchmarks", function () { } const factory = await ethers.getContractFactory(contractName, { libraries }); - let rescueContract = await factory.deploy(); + rescueContract = await factory.deploy(); // Polling interval in ms. rescueContract.provider.pollingInterval = 20; await rescueContract.deployed(); + }); + it(`checks gas usage of ${contractName}.hash`, async function () { const doNothingTx = await rescueContract.doNothing(); const doNothingtxReceipt = await doNothingTx.wait(); - let doNothingGasUsed = doNothingtxReceipt.gasUsed; - - const rescueTx = await rescueContract.hash(10, 15, 20); - const rescueTxReceipt = await rescueTx.wait(); - let rescueGasUsed = rescueTxReceipt.gasUsed; + const doNothingGasUsed = doNothingtxReceipt.gasUsed; - let rescueOnly = rescueGasUsed - doNothingGasUsed; + const rescueGasUsed = await rescueContract.estimateGas.hash(10, 15, 20); - const commitTx = await rescueContract.commit([ - BigInt(10), - BigInt(15), - BigInt(20), - BigInt(0), - BigInt(0), - BigInt(0), - BigInt(0), - BigInt(0), - BigInt(0), - BigInt(0), - BigInt(0), - BigInt(0), - BigInt(0), - BigInt(0), - BigInt(0), - ]); - console.log(commitTx); - const commitTxReceipt = await commitTx.wait(); - let commitGasUsed = commitTxReceipt.gasUsed; + const rescueOnly = rescueGasUsed - doNothingGasUsed; console.log("Rescue gas of ", contractName, ": ", rescueOnly); }); - it(`checks gas usage of ${contractName}.commit on a potentially overflowing input`, async function () { - const libraries = {}; - if (contractName == "TestRescue") { - let rescueLib = await (await ethers.getContractFactory("RescueLib")).deploy(); - libraries["RescueLib"] = rescueLib.address; - } - const factory = await ethers.getContractFactory(contractName, { libraries }); - - let rescueContract = await factory.deploy(); - - // Polling interval in ms. - rescueContract.provider.pollingInterval = 20; - - await rescueContract.deployed(); - - const doNothingTx = await rescueContract.doNothing(); - const doNothingtxReceipt = await doNothingTx.wait(); - let doNothingGasUsed = doNothingtxReceipt.gasUsed; - console.log("About to hash"); - - const rescueTx = await rescueContract.hash(10, 15, 20); - const rescueTxReceipt = await rescueTx.wait(); - let rescueGasUsed = rescueTxReceipt.gasUsed; - - let rescueOnly = rescueGasUsed - doNothingGasUsed; - - console.log("About to commit"); + it(`check ${contractName}.commit works for non-overflowing input`, async function () { + expect( + rescueContract.commit([ + BigInt(10), + BigInt(15), + BigInt(20), + BigInt(0), + BigInt(0), + BigInt(0), + BigInt(0), + BigInt(0), + BigInt(0), + BigInt(0), + BigInt(0), + BigInt(0), + BigInt(0), + BigInt(0), + BigInt(0), + ]) + ).to.not.be.reverted; + }); + it(`check ${contractName}.commit reverts for potentially overflowing input`, async function () { expect( rescueContract.commit([ BigInt(10), diff --git a/contracts/test/greeter.spec.ts b/contracts/test/greeter.spec.ts deleted file mode 100644 index 7ebcc6cc..00000000 --- a/contracts/test/greeter.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2022 Espresso Systems (espressosys.com) -// This file is part of the Configurable Asset Privacy for Ethereum (CAPE) library. -// -// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -// You should have received a copy of the GNU General Public License along with this program. If not, see . - -import { expect } from "chai"; -import { ethers } from "hardhat"; - -/* -import { Greeter } from "../typechain-types"; -*/ - -describe("Greeter (typescript)", function () { - let greeter: any; - - beforeEach(async () => { - const greeterFactory = await ethers.getContractFactory("Greeter"); - greeter = await greeterFactory.deploy("Hello, world!"); - }); - - it("Should return the new greeting once it's changed", async function () { - expect(await greeter.greet()).to.equal("Hello, world!"); - - const setGreetingTx = await greeter.setGreeting("Hola, mundo!"); - - // wait until the transaction is mined - await setGreetingTx.wait(); - - let greeting_str = await greeter.greet(); - expect(greeting_str).to.equal("Hola, mundo!"); - }); -}); diff --git a/poetry.lock b/poetry.lock index 7ef9bcee..cb7656ef 100644 --- a/poetry.lock +++ b/poetry.lock @@ -314,7 +314,7 @@ test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytes [[package]] name = "pre-commit-hooks" -version = "1.1.14" +version = "1.2.0" description = "" category = "main" optional = false @@ -329,7 +329,7 @@ python-Levenshtein-wheels = "*" type = "git" url = "https://github.com/Lucas-C/pre-commit-hooks" reference = "master" -resolved_reference = "31a29ed44815a9fb6d5ce28001ab43bcd71f973b" +resolved_reference = "be28ff2eda4a10f903d66c85b7d29f0f628306c8" [[package]] name = "prettytable" @@ -417,16 +417,23 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "slither-analyzer" version = "0.8.3" -description = "Slither is a Solidity static analysis framework written in Python 3." +description = "" category = "dev" optional = false python-versions = ">=3.6" +develop = false [package.dependencies] -crytic-compile = ">=0.2.3" +crytic-compile = "*" prettytable = ">=0.7.2" pysha3 = ">=1.0.2" +[package.source] +type = "git" +url = "https://github.com/sveitser/slither" +reference = "fix-sarif-empty-results" +resolved_reference = "b24169ae45bce0e3c4656038258359392ba05e6b" + [[package]] name = "tomli" version = "2.0.1" @@ -478,7 +485,7 @@ python-versions = "*" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "3d80af9eb074a15c937a5fcbbd26fbd9110e6eb6ff9dbee8c92add6dcfc3f4c2" +content-hash = "763ac70c840d91b12dc0bd19346d38ce326223e026df1f96c9635066bc0e8e0c" [metadata.files] appnope = [ @@ -704,9 +711,7 @@ six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -slither-analyzer = [ - {file = "slither_analyzer-0.8.3-py3-none-any.whl", hash = "sha256:6216a934e45a85d2d1a8831b14e5f36a98d56dec7ee4eaf9e59194133d346697"}, -] +slither-analyzer = [] tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, diff --git a/pyproject.toml b/pyproject.toml index dc9d2e02..93fdea7a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ pre-commit-hooks = {git = "https://github.com/Lucas-C/pre-commit-hooks"} black = "*" hdwallet = "^1.3.2" ipython = "^7.28.0" -slither-analyzer = "^0.8.3" +slither-analyzer = {git = "https://github.com/sveitser/slither", rev = "fix-sarif-empty-results"} [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/slither.config.json b/slither.config.json new file mode 100644 index 00000000..d81d6704 --- /dev/null +++ b/slither.config.json @@ -0,0 +1,4 @@ +{ + "filter_paths": "ERC20.sol|Token.sol|USDC|mocks|Test|RescueNonOptimized|BytesLib|Ownable.sol", + "detectors_to_exclude": "assembly,similar-names,too-many-digits,naming-convention,solc-version" +}