From 93a0a8487275821c08975b3e8af70f944ab85466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Mart=C3=ADn=20Alconada=20Verzini?= Date: Wed, 3 Jan 2024 14:10:59 -0300 Subject: [PATCH] feat: add CI workflows --- .gas-snapshot | 118 +++++++++++++++++++++++++++++ .github/actions/install/action.yml | 22 ++++++ .github/scripts/comment.js | 56 ++++++++++++++ .github/workflows/forge-fmt.yml | 22 ++++++ .github/workflows/forge-test.yml | 88 +++++++++++++++++++++ .github/workflows/pull_request.yml | 21 +++++ .github/workflows/push.yml | 9 +++ .github/workflows/slither.yml | 34 +++++++++ .github/workflows/test.yml | 34 --------- README.md | 10 +++ codecov.yml | 11 +++ slither.config.json | 6 ++ 12 files changed, 397 insertions(+), 34 deletions(-) create mode 100644 .gas-snapshot create mode 100644 .github/actions/install/action.yml create mode 100644 .github/scripts/comment.js create mode 100644 .github/workflows/forge-fmt.yml create mode 100644 .github/workflows/forge-test.yml create mode 100644 .github/workflows/pull_request.yml create mode 100644 .github/workflows/push.yml create mode 100644 .github/workflows/slither.yml delete mode 100644 .github/workflows/test.yml create mode 100644 codecov.yml create mode 100644 slither.config.json diff --git a/.gas-snapshot b/.gas-snapshot new file mode 100644 index 000000000..a3546a744 --- /dev/null +++ b/.gas-snapshot @@ -0,0 +1,118 @@ +DeveloperDeployTest:testUp() (gas: 24279) +ETHPriceIsRightTest:testAnyoneCanChangeGuessBeforeEnd() (gas: 131807) +ETHPriceIsRightTest:testAnyoneCanEnterGuessBeforeEnd() (gas: 127341) +ETHPriceIsRightTest:testFailCannotEnterGuessAfterTime() (gas: 11629) +ETHPriceIsRightTest:testGuessCalculations() (gas: 156151) +ETHPriceIsRightTest:testUp() (gas: 16852) +EngenCreditsTest:testCanBurnAfterSettingFlag() (gas: 70853) +EngenCreditsTest:testCanTransferAfterSettingFlag() (gas: 100027) +EngenCreditsTest:testFailOthersCannotUpgrade() (gas: 2102028) +EngenCreditsTest:testNobodyCanBurn() (gas: 70679) +EngenCreditsTest:testNobodyCanTransfer() (gas: 71888) +EngenCreditsTest:testOthersCannotMint() (gas: 25978) +EngenCreditsTest:testOwnerCanMint() (gas: 68218) +EngenCreditsTest:testOwnerCanUpgradeEngen() (gas: 2133223) +EngenCreditsTest:testUp() (gas: 22908) +EngenCreditsTest:testWalletCanGetPoints() (gas: 631586) +EngenCreditsTest:testWalletCanGetPointsWithOverride() (gas: 657489) +EngenCreditsTest:testWalletCannotGetPointsTwice() (gas: 718288) +FaucetTest:testClaim() (gas: 81023) +FaucetTest:testClaimOnBehalf() (gas: 115966) +FaucetTest:testFailIfClaimedTwice() (gas: 77198) +FaucetTest:testFailOwnerCannotStartWithoutAmount() (gas: 19407) +FaucetTest:testFailStartFaucetByOthers() (gas: 16870) +FaucetTest:testOwnerCanStartFaucet() (gas: 42651) +FaucetTest:testUp() (gas: 6294) +KYCViewerTest:testFailOthersCannotUpgradeFactory() (gas: 1029248) +KYCViewerTest:testIsKYCBothOwnerAndWallet() (gas: 82707) +KYCViewerTest:testOwnerCanUpgradeViewer() (gas: 1065414) +KYCViewerTest:testUp() (gas: 40633) +KintoEntryPointTest:testCannotResetWalletFactoryAddress() (gas: 13610) +KintoEntryPointTest:testUp() (gas: 9940) +KintoIDTest:testAuthorizedCanUpgrade() (gas: 3932582) +KintoIDTest:testBurnFailsWithoutMinting() (gas: 26911) +KintoIDTest:testBurnKYC() (gas: 250194) +KintoIDTest:testBurningTwiceFails() (gas: 254209) +KintoIDTest:testDappSignature() (gas: 166) +KintoIDTest:testFailOnlyProviderCanMonitor() (gas: 48382) +KintoIDTest:testFailOthersCannotUpgrade() (gas: 3885070) +KintoIDTest:testFailProviderCanAddTraitUnknownUser() (gas: 22719) +KintoIDTest:testFailTransfersAreDisabled() (gas: 297354) +KintoIDTest:testFailUserCannotAddSanction() (gas: 47795) +KintoIDTest:testFailUserCannotAddTrait() (gas: 47797) +KintoIDTest:testFailUserCannotRemoveSanction() (gas: 22608) +KintoIDTest:testFailUserCannotRemoveTrait() (gas: 326993) +KintoIDTest:testIsSanctionsMonitored() (gas: 28227) +KintoIDTest:testMintCompanyKYC() (gas: 284477) +KintoIDTest:testMintIndividualKYC() (gas: 282508) +KintoIDTest:testMintIndividualKYCWithExpiredSignature() (gas: 47491) +KintoIDTest:testMintIndividualKYCWithInvalidNonce() (gas: 291771) +KintoIDTest:testMintIndividualKYCWithInvalidSender() (gas: 48206) +KintoIDTest:testMintIndividualKYCWithInvalidSigner() (gas: 60535) +KintoIDTest:testMonitorNoChanges() (gas: 24089) +KintoIDTest:testOnlyProviderCanBurnKYC() (gas: 303449) +KintoIDTest:testOwnerCanUpgrade() (gas: 3893769) +KintoIDTest:testProviderCanAddSanction() (gas: 323296) +KintoIDTest:testProviderCanAddTrait() (gas: 291380) +KintoIDTest:testProviderCanRemoveSancion() (gas: 311233) +KintoIDTest:testProviderCanRemoveTrait() (gas: 282942) +KintoIDTest:testSettingTraitsAndSanctions() (gas: 317512) +KintoIDTest:testUp() (gas: 17956) +KintoWalletFactoryTest:testAllWalletsUpgrade() (gas: 3517833) +KintoWalletFactoryTest:testDeployCustomContract() (gas: 136473) +KintoWalletFactoryTest:testFailCreateWalletThroughDeploy() (gas: 51285) +KintoWalletFactoryTest:testFailOthersCannotUpgradeFactory() (gas: 2636897) +KintoWalletFactoryTest:testFailOthersCannotUpgradeWallets() (gas: 3498853) +KintoWalletFactoryTest:testOwnerCanUpgradeFactory() (gas: 2673030) +KintoWalletFactoryTest:testRandomSignerCannotFundWallet() (gas: 77154) +KintoWalletFactoryTest:testSignerCanFundWallet() (gas: 71109) +KintoWalletFactoryTest:testSignerCannotFundInvalidWallet() (gas: 25030) +KintoWalletFactoryTest:testSignerCannotFundWalletWithoutEth() (gas: 18216) +KintoWalletFactoryTest:testUp() (gas: 20247) +KintoWalletFactoryTest:testWhitelistedSignerCanFundWallet() (gas: 463743) +KintoWalletTest:testAddingOneFunder() (gas: 393298) +KintoWalletTest:testAddingOneSigner() (gas: 404205) +KintoWalletTest:testApproveAndRevokeTokens() (gas: 580610) +KintoWalletTest:testApproveTokens() (gas: 530958) +KintoWalletTest:testChangingPolicyWithThreeSigners() (gas: 442028) +KintoWalletTest:testChangingPolicyWithTwoSigners() (gas: 413114) +KintoWalletTest:testFailApproveTokensWithoutWhitelist() (gas: 157159) +KintoWalletTest:testFailCallingApproveDirectly() (gas: 625818) +KintoWalletTest:testFailChangingPolicyWithoutRightSigners() (gas: 174419) +KintoWalletTest:testFailDirectCall() (gas: 65568) +KintoWalletTest:testFailMultipleTransactionsExecuteBatchPaymasterRefuses() (gas: 363188) +KintoWalletTest:testFailMultisigTransaction() (gas: 605529) +KintoWalletTest:testFailMultisigTransactionWhen2OutOf3Signers() (gas: 620528) +KintoWalletTest:testFailOthersCannotUpgrade() (gas: 3151175) +KintoWalletTest:testFailOwnerCannotUpgrade() (gas: 3467167) +KintoWalletTest:testFailRecoverNotEnoughTime() (gas: 430100) +KintoWalletTest:testFailRecoverNotRecoverer() (gas: 79216) +KintoWalletTest:testFailRecoverWithoutBurningOldOwner() (gas: 368060) +KintoWalletTest:testFailRecoverWithoutMintingNewOwner() (gas: 218345) +KintoWalletTest:testFailSendingTransactionDirectly() (gas: 184911) +KintoWalletTest:testFailSettingAppKeyNoWhitelist() (gas: 389794) +KintoWalletTest:testFailTransactionViaPaymasterNoapproval() (gas: 457146) +KintoWalletTest:testFailWithDuplicateSigner() (gas: 379042) +KintoWalletTest:testFailWithEmptyArray() (gas: 383567) +KintoWalletTest:testFailWithManyOwners() (gas: 379274) +KintoWalletTest:testFailWithoutKYCSigner() (gas: 377318) +KintoWalletTest:testMultipleTransactionsExecuteBatchPaymaster() (gas: 534232) +KintoWalletTest:testMultipleTransactionsViaPaymaster() (gas: 756771) +KintoWalletTest:testMultisigTransaction() (gas: 859779) +KintoWalletTest:testMultisigTransactionWith1SignerButSeveralOwners() (gas: 864858) +KintoWalletTest:testMultisigTransactionWith2SignersWithAppkey() (gas: 969063) +KintoWalletTest:testMultisigTransactionWith3Signers() (gas: 901623) +KintoWalletTest:testRecoverAccountSuccessfully() (gas: 402899) +KintoWalletTest:testSettingAppKey() (gas: 491395) +KintoWalletTest:testTransactionViaPaymaster() (gas: 694244) +KintoWalletTest:testUp() (gas: 32038) +KintoWalletTest:testWalletOwnersAreWhitelisted() (gas: 39988) +SponsorPaymasterExploitTest:testExploit() (gas: 283756) +SponsorPaymasterTest:testFailOthersCannotUpgrade() (gas: 2205926) +SponsorPaymasterTest:testFailUserCanDepositStakeAndWithdrawWithoutRoll() (gas: 129377) +SponsorPaymasterTest:testFailUserCanWithdrawAllInEmergency() (gas: 137198) +SponsorPaymasterTest:testOwnerCanDepositStakeAndWithdraw() (gas: 95286) +SponsorPaymasterTest:testOwnerCanUpgrade() (gas: 2242110) +SponsorPaymasterTest:testOwnerCanWithdrawAllInEmergency() (gas: 123988) +SponsorPaymasterTest:testUp() (gas: 10454) +SponsorPaymasterTest:testUserCanDepositStakeAndWithdraw() (gas: 108566) \ No newline at end of file diff --git a/.github/actions/install/action.yml b/.github/actions/install/action.yml new file mode 100644 index 000000000..e33d9d4d5 --- /dev/null +++ b/.github/actions/install/action.yml @@ -0,0 +1,22 @@ +name: Install dependencies +description: Install foundry & other dependencies for use in other actions + +runs: + using: composite + + steps: + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Restore forge compilation cache + uses: actions/cache/restore@v3 + with: + path: | + cache + out + key: forge-${{ github.ref_name }} + restore-keys: | + forge-${{ github.base_ref }} + forge- \ No newline at end of file diff --git a/.github/scripts/comment.js b/.github/scripts/comment.js new file mode 100644 index 000000000..415a09142 --- /dev/null +++ b/.github/scripts/comment.js @@ -0,0 +1,56 @@ +module.exports = async ({ github, context, header, body }) => { + const comment = [header, body].join("\n"); + + let issueNumber; + + if (context.eventName === 'pull_request') { + // For pull_request events, the number is directly available + issueNumber = context.payload.pull_request.number; + console.log("Pull Request Number: ", issueNumber); + } else if (context.eventName === 'push') { + // For push events, try to get the associated pull requests + const pullRequests = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + head: `${context.repo.owner}:${context.ref.replace('refs/heads/', '')}` + }); + + if (pullRequests.data.length > 0) { + // If there are open pull requests associated with the push, take the first one + issueNumber = pullRequests.data[0].number; + console.log("Associated Pull Request Number: ", issueNumber); + } else { + console.log("No associated pull requests found for this push event."); + return; // Exit early if no associated PR is found + } + } else { + // If the event is neither pull_request nor push, log it and exit + console.log(`Unhandled event type: ${context.eventName}`); + return; + } + + // Get the existing comments + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + }); + + // Find any comment already made by the bot + const botComment = comments.find( + comment => comment.user.id === 41898282 && comment.body.startsWith(header) + ); + + const commentFn = botComment ? "updateComment" : "createComment"; + + // Create or update the comment + await github.rest.issues[commentFn]({ + owner: context.repo.owner, + repo: context.repo.repo, + body: comment, + ...(botComment + ? { comment_id: botComment.id } + : { issue_number: issueNumber }), + }); +}; diff --git a/.github/workflows/forge-fmt.yml b/.github/workflows/forge-fmt.yml new file mode 100644 index 000000000..316c10eb0 --- /dev/null +++ b/.github/workflows/forge-fmt.yml @@ -0,0 +1,22 @@ +name: Forge format + +on: + workflow_call: + +jobs: + forge-fmt: + name: Formatting + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Check formatting + run: forge fmt --check \ No newline at end of file diff --git a/.github/workflows/forge-test.yml b/.github/workflows/forge-test.yml new file mode 100644 index 000000000..4aa934558 --- /dev/null +++ b/.github/workflows/forge-test.yml @@ -0,0 +1,88 @@ +name: Test Suite + +on: + workflow_call: + +env: + FOUNDRY_PROFILE: ci + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Compile + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - uses: ./.github/actions/install + + - name: Build contracts + run: forge build --sizes + + - name: Check gas snapshots + run: forge snapshot --diff + + - name: Save forge compilation cache + uses: actions/cache/save@v3 + with: + path: | + cache + out + key: forge-${{ github.ref_name }} + + test: + needs: build + + name: Test (${{ inputs.network }}) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - uses: ./.github/actions/install + + - name: Run tests + run: forge test + + coverage: + needs: + - test + #- test-unit + #- test-internal + #- test-integration + #- test-invariant + # if: inputs.coverageThreshold != '' + + name: Coverage (${{ inputs.network }}) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - uses: ./.github/actions/install + + - name: Generate LCOV report + run: forge coverage --report lcov + + - name: Upload report to Codecov + uses: codecov/codecov-action@v3 + with: + directory: . + fail_ci_if_error: true + verbose: true + + # - name: Check coverage threshold + # uses: terencetcf/github-actions-lcov-minimum-coverage-checker@v1 + # with: + # coverage-file: lcov.info + # minimum-coverage: 90 \ No newline at end of file diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 000000000..3186a6700 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,21 @@ +name: Pull request + +on: + pull_request: + +jobs: + forge-fmt: + name: Forge format + uses: ./.github/workflows/forge-fmt.yml + secrets: inherit + + forge-test: + if: github.head_ref != 'main' # already triggered by push + name: Forge tests + uses: ./.github/workflows/forge-test.yml + secrets: inherit + + analyse: + name: Slither analysis + uses: ./.github/workflows/slither.yml + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 000000000..e31ba069c --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,9 @@ +name: Push + +on: + push: + +jobs: + forge-kinto-mainnet: + name: Forge tests + uses: ./.github/workflows/forge-fmt.yml \ No newline at end of file diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml new file mode 100644 index 000000000..c62db93ec --- /dev/null +++ b/.github/workflows/slither.yml @@ -0,0 +1,34 @@ +name: Slither Analysis + +on: + workflow_call: + +permissions: + issues: write + pull-requests: write + +jobs: + analyze: + name: Analyse + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Run Slither + uses: crytic/slither-action@v0.3.0 + id: slither + with: + node-version: 16 + fail-on: none + slither-args: --checklist --markdown-root ${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/ + + - name: Create/update checklist as PR comment + uses: actions/github-script@v6 + env: + REPORT: ${{ steps.slither.outputs.stdout }} + with: + script: | + const script = require('.github/scripts/comment') + const header = '# Slither report' + const body = process.env.REPORT + await script({ github, context, header, body }) \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 09880b1d7..000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: test - -on: workflow_dispatch - -env: - FOUNDRY_PROFILE: ci - -jobs: - check: - strategy: - fail-fast: true - - name: Foundry project - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - - name: Run Forge build - run: | - forge --version - forge build --sizes - id: build - - - name: Run Forge tests - run: | - forge test -vvv - id: test diff --git a/README.md b/README.md index 4abf6eb92..fd47883d0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ ![Slide 1](https://github.com/KintoXYZ/kinto-id/assets/541599/c9345010-21c6-411c-bbf8-31a6727d8c48) +[![codecov](https://codecov.io/gh/KintoXYZ/kinto-core/graph/badge.svg?token=JXQ1EQTRV1)](https://codecov.io/gh/KintoXYZ/kinto-core) + # What is Kinto? Kinto is an **Ethereum L2 rollup designed to accelerate the transition to an on-chain financial system**. It features **permissionless KYC/AML and native account abstraction** to solve the two biggest blockers to mainstream adoption: compliance and user experience. @@ -75,6 +77,14 @@ In order to run the tests, execute the following command: forge test ``` +## Static Analysis + +In order to run Slither for static analysis, execute the following command: + +``` +slither --checklist --solc-remaps "$(tr '\n' ' ' < remappings.txt | xargs)" ./src/ +``` + ### Calling the Kinto ID smart contract Check that the contract is deployed: diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..ad1135909 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,11 @@ +ignore: + - "test" # ignore test/ folder + - "script" # ignore scripts/ folder + - "lib" # ignore libs/ folder + +comment: + layout: " diff, flags, files" + behavior: default + require_changes: false # if true: only post the comment if coverage changes + require_base: false # [true :: must have a base report to post] + require_head: true # [true :: must have a head report to post] \ No newline at end of file diff --git a/slither.config.json b/slither.config.json new file mode 100644 index 000000000..56351e2d8 --- /dev/null +++ b/slither.config.json @@ -0,0 +1,6 @@ +{ + "exclude_informational": true, + "exclude_low": true, + "exclude_medium": false, + "exclude_high": false +} \ No newline at end of file