diff --git a/.github/scripts/slither_pr_comment.js b/.github/scripts/slither_pr_comment.js new file mode 100644 index 0000000..4f1caf1 --- /dev/null +++ b/.github/scripts/slither_pr_comment.js @@ -0,0 +1,32 @@ +module.exports = async ({ github, context, header, body }) => { + const body2 = body + .replaceAll("%8D", "\r") + .replaceAll("%0A", "\n") + .replaceAll("%25", "%"); + const comment = [header, body2].join("\n"); + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.number, + }); + + const botComment = comments.find( + (comment) => + // github-actions bot user + comment.user.id === 41898282 && comment.body.startsWith(header) + ); + + const requestBody = { + owner: context.repo.owner, + repo: context.repo.repo, + body: comment, + }; + if (botComment) { + requestBody.comment_id = botComment.id; + await github.rest.issues.updateComment(requestBody); + } else { + requestBody.issue_number = context.payload.number; + await github.rest.issues.createComment(requestBody); + } +}; diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml new file mode 100644 index 0000000..979928e --- /dev/null +++ b/.github/workflows/slither.yml @@ -0,0 +1,44 @@ +name: Slither + +on: + push: + branches: + - main + pull_request: + +jobs: + slither: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Run Slither Analysis + uses: crytic/slither-action@v0.4.1 + id: slither + with: + slither-config: slither.config.json + sarif: results.sarif + fail-on: none + slither-args: --checklist --markdown-root ${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/ + + - name: Format slither output + id: formatted_slither + run: | + value=$(echo "${{ steps.slither.outputs.stdout }}" | sed -e '1d') + value="${value//'%'/'%25'}" + value="${value//$'\n'/'%0A'}" + value="${value//$'\r'/'%0D'}" + echo "value=${value}" >> $GITHUB_OUTPUT + count=$(jq '[.runs[].results[]] | length' results.sarif 2>/dev/null || echo 0) + echo "results_count=${count}" >> $GITHUB_OUTPUT + + - name: Create/update checklist as PR comment + if: ${{ github.event_name == 'pull_request' && steps.formatted_slither.outputs.results_count != '0' }} + uses: actions/github-script@v6 + with: + script: | + const script = require(".github/scripts/slither_pr_comment") + const header = '# Slither report' + const body = `${{ steps.formatted_slither.outputs.value }}` + const comment = [header, body].join("\n"); + await script({github, context, header, body}) diff --git a/Makefile b/Makefile index 66283e7..992c60c 100644 --- a/Makefile +++ b/Makefile @@ -19,3 +19,7 @@ else @echo "'SOURCE={ContractName}' is required, e.g. make abi SOURCE=CrossSimpleModule" @exit 1 endif + +.PHONY: slither +slither: + slither . diff --git a/README.md b/README.md index 7259d44..74a223a 100644 --- a/README.md +++ b/README.md @@ -39,3 +39,10 @@ interface IContractModule { To generate encoders and decoders in solidity from proto files, you need to use the code generator [solidity-protobuf](https://github.com/datachainlab/solidity-protobuf). Currently, [this version](https://github.com/datachainlab/solidity-protobuf/commit/3def6706178e5407497f3d01b8f0ceb17b32108d) is required. + +Install Slither and use it for static analysis. + +``` +pip3 install slither-analyzer +make slither +``` diff --git a/slither.config.json b/slither.config.json new file mode 100644 index 0000000..59e026f --- /dev/null +++ b/slither.config.json @@ -0,0 +1,5 @@ +{ + "exclude_dependencies": true, + "exclude_informational": true, + "filter_paths": "node_modules|src/proto" +} diff --git a/src/Migrations.sol b/src/Migrations.sol deleted file mode 100644 index 87d493b..0000000 --- a/src/Migrations.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.4.22 <0.9.0; - -contract Migrations { - address public owner = msg.sender; - uint256 public last_completed_migration; - - modifier restricted() { - require(msg.sender == owner, "This function is restricted to the contract's owner"); - _; - } - - function setCompleted(uint256 completed) public restricted { - last_completed_migration = completed; - } -} diff --git a/src/core/CrossSimpleModule.sol b/src/core/CrossSimpleModule.sol index 0c600b3..0b039e2 100644 --- a/src/core/CrossSimpleModule.sol +++ b/src/core/CrossSimpleModule.sol @@ -21,8 +21,9 @@ contract CrossSimpleModule is CrossModule, SimpleContractRegistry, TxAtomicSimpl pure returns (bytes memory acknowledgement) { - PacketAcknowledgementCall.Data memory ack; - ack.status = status; + PacketAcknowledgementCall.Data memory ack = PacketAcknowledgementCall.Data({ + status: status + }); return packPacketAcknowledgementCall(ack); } } diff --git a/src/core/IBCKeeper.sol b/src/core/IBCKeeper.sol index b82833b..d591128 100644 --- a/src/core/IBCKeeper.sol +++ b/src/core/IBCKeeper.sol @@ -5,7 +5,7 @@ import {IIBCHandler} from "@hyperledger-labs/yui-ibc-solidity/contracts/core/25- // IBCKeeper keeps the contracts of IBC abstract contract IBCKeeper { - IIBCHandler ibcHandler; + IIBCHandler internal immutable ibcHandler; constructor(IIBCHandler handler_) { ibcHandler = handler_; diff --git a/src/core/TxAtomicSimple.sol b/src/core/TxAtomicSimple.sol index 234643f..523857a 100644 --- a/src/core/TxAtomicSimple.sol +++ b/src/core/TxAtomicSimple.sol @@ -31,14 +31,18 @@ abstract contract TxAtomicSimple is IBCKeeper, PacketHandler, ContractRegistry { ); PacketDataCall.Data memory pdc = PacketDataCall.decode(anyPayload.value); - PacketAcknowledgementCall.Data memory ack; + PacketAcknowledgementCall.Data memory ack = PacketAcknowledgementCall.Data({ + status: PacketAcknowledgementCall.CommitStatus.COMMIT_STATUS_UNKNOWN + }); try module.onContractCall( CrossContext(pdc.tx_id, txIndexParticipant, pdc.tx.signers), pdc.tx.call_info ) returns (bytes memory ret) { ack.status = PacketAcknowledgementCall.CommitStatus.COMMIT_STATUS_OK; + // slither-disable-next-line reentrancy-events emit OnContractCall(pdc.tx_id, txIndexParticipant, true, ret); } catch (bytes memory) { ack.status = PacketAcknowledgementCall.CommitStatus.COMMIT_STATUS_FAILED; + // slither-disable-next-line reentrancy-events emit OnContractCall(pdc.tx_id, txIndexParticipant, false, new bytes(0)); } @@ -72,7 +76,7 @@ abstract contract TxAtomicSimple is IBCKeeper, PacketHandler, ContractRegistry { pure returns (bytes memory) { - HeaderField.Data[] memory fields; + HeaderField.Data[] memory fields = new HeaderField.Data[](0); return Acknowledgement.encode( Acknowledgement.Data({ is_success: true,