[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-20-cicd-smart-contracts-gas-regression":3},{"article":4,"author":60},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":16,"meta_description":17,"focus_keyword":18,"og_image":19,"canonical_url":19,"robots_meta":20,"created_at":15,"updated_at":15,"tags":21,"category_name":39,"related_articles":40},"d0000000-0000-0000-0000-000000000120","a0000000-0000-0000-0000-000000000002","Deep EVM #20: CI\u002FCD for Smart Contracts — Testing, Gas Regression, and Safety","deep-evm-20-cicd-smart-contracts-gas-regression","Build a production-grade CI\u002FCD pipeline for smart contracts with gas regression tracking, static analysis, automated verification, and deployment safety checks.","## Why Smart Contracts Need Their Own CI\u002FCD\n\nSmart contracts are not like regular software. Once deployed, they are immutable. A bug in a web app means a hotfix and a redeployment. A bug in a smart contract means lost funds, permanent state corruption, or a costly proxy upgrade. This changes the entire CI\u002FCD philosophy: the pipeline is not just about catching regressions — it is the last line of defense before irreversible deployment.\n\nA production-grade smart contract CI\u002FCD pipeline must include: compilation and type checking, comprehensive test suites (unit, fuzz, invariant), gas regression tracking, static analysis for vulnerability patterns, deployment simulation, and automated contract verification.\n\n## Pipeline Architecture\n\nHere is a complete GitHub Actions workflow for a Foundry-based smart contract project:\n\n```yaml\n# .github\u002Fworkflows\u002Fci.yml\nname: Smart Contract CI\n\non:\n  push:\n    branches: [main]\n  pull_request:\n\nenv:\n  FOUNDRY_PROFILE: ci\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n\n      - uses: foundry-rs\u002Ffoundry-toolchain@v1\n        with:\n          version: nightly\n\n      - name: Install Huff\n        run: |\n          curl -L get.huff.sh | bash\n          echo \"$HOME\u002F.huff\u002Fbin\" >> $GITHUB_PATH\n\n      - name: Build\n        run: forge build --sizes\n\n      - name: Check contract sizes\n        run: |\n          forge build --sizes 2>&1 | while read line; do\n            size=$(echo \"$line\" | grep -oP '\\d+\\.\\d+' | head -1)\n            if [ ! -z \"$size\" ] && (( $(echo \"$size > 24.0\" | bc -l) )); then\n              echo \"::error::Contract exceeds 24KB limit: $line\"\n              exit 1\n            fi\n          done\n\n  test:\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n      - uses: foundry-rs\u002Ffoundry-toolchain@v1\n\n      - name: Unit tests\n        run: forge test --match-path \"test\u002Funit\u002F*\" -vvv\n\n      - name: Fuzz tests\n        run: |\n          forge test --match-path \"test\u002Ffuzz\u002F*\" \\\n            --fuzz-runs 50000 -vv\n\n      - name: Invariant tests\n        run: |\n          forge test --match-path \"test\u002Finvariant\u002F*\" \\\n            --invariant-runs 512 \\\n            --invariant-depth 256 -vv\n\n      - name: Fork tests\n        run: |\n          forge test --match-path \"test\u002Ffork\u002F*\" \\\n            --fork-url ${{ secrets.ETH_RPC_URL }} -vvv\n        env:\n          ETH_RPC_URL: ${{ secrets.ETH_RPC_URL }}\n\n  gas:\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n      - uses: foundry-rs\u002Ffoundry-toolchain@v1\n\n      - name: Gas snapshot\n        run: forge snapshot\n\n      - name: Compare gas\n        run: forge snapshot --check --tolerance 2\n\n      - name: Upload snapshot\n        uses: actions\u002Fupload-artifact@v4\n        with:\n          name: gas-snapshot\n          path: .gas-snapshot\n\n  static-analysis:\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n\n      - name: Slither analysis\n        uses: crytic\u002Fslither-action@v0.4.0\n        with:\n          sarif: results.sarif\n          fail-on: medium\n\n      - name: Upload SARIF\n        uses: github\u002Fcodeql-action\u002Fupload-sarif@v3\n        with:\n          sarif_file: results.sarif\n\n      - name: Aderyn analysis\n        run: |\n          cargo install aderyn\n          aderyn . --output report.md\n\n      - name: Upload Aderyn report\n        uses: actions\u002Fupload-artifact@v4\n        with:\n          name: aderyn-report\n          path: report.md\n```\n\n## Gas Regression Tracking with forge snapshot\n\nGas regression is a critical metric for smart contracts. A 5% gas increase in a DEX router's swap function costs real money at scale. Track it systematically:\n\n```bash\n# Generate baseline (commit to repo)\nforge snapshot > .gas-snapshot\ngit add .gas-snapshot\ngit commit -m \"chore: update gas snapshot\"\n\n# In CI, compare against baseline\nforge snapshot --check .gas-snapshot --tolerance 2\n```\n\nThe `--tolerance 2` flag allows up to 2% gas increase before failing. For hot paths like MEV bot operations, set tolerance to 0%.\n\nFor PR comments showing gas diffs, create a custom action:\n\n```yaml\n  gas-report:\n    runs-on: ubuntu-latest\n    if: github.event_name == 'pull_request'\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n      - uses: foundry-rs\u002Ffoundry-toolchain@v1\n\n      - name: Generate gas diff\n        run: |\n          forge snapshot --diff .gas-snapshot > gas-diff.txt 2>&1 || true\n          echo \"## Gas Report\" > comment.md\n          echo '```' >> comment.md\n          cat gas-diff.txt >> comment.md\n          echo '```' >> comment.md\n\n      - name: Post PR comment\n        uses: marocchino\u002Fsticky-pull-request-comment@v2\n        with:\n          path: comment.md\n```\n\n## Static Analysis: Slither and Aderyn\n\n### Slither\n\nSlither is the industry-standard static analyzer for Solidity. It detects vulnerability patterns like reentrancy, unchecked external calls, and access control issues:\n\n```bash\nslither . --filter-paths \"test\u002F|script\u002F|lib\u002F\" \\\n  --exclude naming-convention,solc-version \\\n  --fail-on medium\n```\n\nCommon findings and how to handle them:\n\n| Finding | Severity | Action |\n|---------|----------|--------|\n| Reentrancy | High | Fix immediately, use CEI pattern |\n| Unchecked return | Medium | Add return value check |\n| Naming convention | Info | Suppress with `--exclude` |\n| Unused state variable | Low | Remove or suppress |\n\nFor Huff contracts, Slither cannot analyze the bytecode directly. Instead, analyze the Solidity interface contracts and integration tests that call the Huff contracts.\n\n### Aderyn\n\nAderyn is a Rust-based static analyzer that complements Slither with additional checks:\n\n```bash\naderyn . --output report.json --format json\n```\n\nAderyn is particularly good at catching gas optimization opportunities and detecting centralization risks.\n\n## Deployment Checklists\n\nAutomate pre-deployment checks with a script:\n\n```solidity\n\u002F\u002F script\u002FDeployChecklist.s.sol\ncontract DeployChecklist is Script {\n    function run() external view {\n        \u002F\u002F 1. Verify compiler settings\n        require(block.chainid == 1, \"Wrong chain!\");\n\n        \u002F\u002F 2. Verify constructor args\n        address expectedOwner = vm.envAddress(\"OWNER\");\n        require(expectedOwner != address(0), \"Owner not set\");\n\n        \u002F\u002F 3. Verify all dependencies are deployed\n        require(\n            IWETH(WETH).totalSupply() > 0,\n            \"WETH not deployed\"\n        );\n\n        console.log(\"All checks passed\");\n    }\n}\n```\n\n```bash\n# Dry run against mainnet fork\nforge script script\u002FDeployChecklist.s.sol \\\n  --fork-url $ETH_RPC_URL -vvv\n```\n\n## Automated Verification on Etherscan\n\nPost-deployment, automatically verify contracts on Etherscan so users can read the source:\n\n```bash\nforge verify-contract \\\n  --chain mainnet \\\n  --num-of-optimizations 200 \\\n  --watch \\\n  --compiler-version v0.8.24 \\\n  --etherscan-api-key $ETHERSCAN_KEY \\\n  $CONTRACT_ADDRESS \\\n  src\u002FMyContract.sol:MyContract\n```\n\nFor contracts with constructor arguments:\n\n```bash\n# Encode constructor args\ncast abi-encode \"constructor(address,uint256)\" $OWNER $INITIAL_SUPPLY\n\n# Pass encoded args to verify\nforge verify-contract \\\n  --constructor-args $(cast abi-encode \"constructor(address,uint256)\" $OWNER $INITIAL_SUPPLY) \\\n  $CONTRACT_ADDRESS \\\n  src\u002FMyContract.sol:MyContract\n```\n\nAutomate this in CI by adding a deployment job that triggers on tag pushes:\n\n```yaml\n  deploy-verify:\n    runs-on: ubuntu-latest\n    if: startsWith(github.ref, 'refs\u002Ftags\u002Fv')\n    needs: [test, gas, static-analysis]\n    environment: mainnet\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n      - uses: foundry-rs\u002Ffoundry-toolchain@v1\n\n      - name: Deploy\n        run: |\n          forge script script\u002FDeploy.s.sol \\\n            --rpc-url ${{ secrets.ETH_RPC_URL }} \\\n            --broadcast \\\n            --verify \\\n            --etherscan-api-key ${{ secrets.ETHERSCAN_KEY }} \\\n            -vvv\n        env:\n          PRIVATE_KEY: ${{ secrets.DEPLOYER_KEY }}\n```\n\n## Deployment Simulation\n\nBefore deploying to mainnet, simulate the entire deployment against a fork:\n\n```bash\n# Simulate deployment\nforge script script\u002FDeploy.s.sol \\\n  --fork-url $ETH_RPC_URL \\\n  --sender $DEPLOYER \\\n  -vvvv\n\n# If simulation passes, broadcast\nforge script script\u002FDeploy.s.sol \\\n  --rpc-url $ETH_RPC_URL \\\n  --broadcast \\\n  --slow \\\n  --verify\n```\n\nThe `--slow` flag submits transactions one at a time and waits for confirmation, which is safer for multi-step deployments.\n\n## Monitoring Post-Deployment\n\nAfter deployment, set up automated monitoring:\n\n```yaml\n  post-deploy-check:\n    runs-on: ubuntu-latest\n    needs: deploy-verify\n    steps:\n      - name: Verify deployment\n        run: |\n          # Check contract is verified on Etherscan\n          STATUS=$(curl -s \"https:\u002F\u002Fapi.etherscan.io\u002Fapi?module=contract&action=getabi&address=$CONTRACT\" | jq -r '.status')\n          [ \"$STATUS\" = \"1\" ] || exit 1\n\n          # Check contract responds correctly\n          OWNER=$(cast call $CONTRACT \"owner()\" --rpc-url $RPC)\n          [ \"$OWNER\" = \"$EXPECTED_OWNER\" ] || exit 1\n\n          echo \"Deployment verified successfully\"\n```\n\n## Security Tooling Summary\n\n| Tool | Type | Best For |\n|------|------|----------|\n| Slither | Static analysis | Vulnerability patterns, Solidity |\n| Aderyn | Static analysis | Gas, centralization risks |\n| Foundry Fuzz | Dynamic testing | Edge cases, boundary values |\n| Foundry Invariant | Stateful fuzzing | State-dependent bugs |\n| Echidna | Fuzzer | Property testing (alternative) |\n| Mythril | Symbolic execution | Path exploration |\n| Certora | Formal verification | Mathematical proofs |\n\n## Conclusion\n\nA production-grade smart contract CI\u002FCD pipeline is fundamentally different from traditional software CI. Every stage serves as a safety gate before irreversible deployment. Gas snapshots catch performance regressions, static analyzers flag vulnerability patterns, fuzzers explore edge cases, and deployment simulations verify behavior against real state. The pipeline's job is simple: make it harder to deploy a bug than to catch one.","\u003Ch2 id=\"why-smart-contracts-need-their-own-ci-cd\">Why Smart Contracts Need Their Own CI\u002FCD\u003C\u002Fh2>\n\u003Cp>Smart contracts are not like regular software. Once deployed, they are immutable. A bug in a web app means a hotfix and a redeployment. A bug in a smart contract means lost funds, permanent state corruption, or a costly proxy upgrade. This changes the entire CI\u002FCD philosophy: the pipeline is not just about catching regressions — it is the last line of defense before irreversible deployment.\u003C\u002Fp>\n\u003Cp>A production-grade smart contract CI\u002FCD pipeline must include: compilation and type checking, comprehensive test suites (unit, fuzz, invariant), gas regression tracking, static analysis for vulnerability patterns, deployment simulation, and automated contract verification.\u003C\u002Fp>\n\u003Ch2 id=\"pipeline-architecture\">Pipeline Architecture\u003C\u002Fh2>\n\u003Cp>Here is a complete GitHub Actions workflow for a Foundry-based smart contract project:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yaml\"># .github\u002Fworkflows\u002Fci.yml\nname: Smart Contract CI\n\non:\n  push:\n    branches: [main]\n  pull_request:\n\nenv:\n  FOUNDRY_PROFILE: ci\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n\n      - uses: foundry-rs\u002Ffoundry-toolchain@v1\n        with:\n          version: nightly\n\n      - name: Install Huff\n        run: |\n          curl -L get.huff.sh | bash\n          echo \"$HOME\u002F.huff\u002Fbin\" &gt;&gt; $GITHUB_PATH\n\n      - name: Build\n        run: forge build --sizes\n\n      - name: Check contract sizes\n        run: |\n          forge build --sizes 2&gt;&amp;1 | while read line; do\n            size=$(echo \"$line\" | grep -oP '\\d+\\.\\d+' | head -1)\n            if [ ! -z \"$size\" ] &amp;&amp; (( $(echo \"$size &gt; 24.0\" | bc -l) )); then\n              echo \"::error::Contract exceeds 24KB limit: $line\"\n              exit 1\n            fi\n          done\n\n  test:\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n      - uses: foundry-rs\u002Ffoundry-toolchain@v1\n\n      - name: Unit tests\n        run: forge test --match-path \"test\u002Funit\u002F*\" -vvv\n\n      - name: Fuzz tests\n        run: |\n          forge test --match-path \"test\u002Ffuzz\u002F*\" \\\n            --fuzz-runs 50000 -vv\n\n      - name: Invariant tests\n        run: |\n          forge test --match-path \"test\u002Finvariant\u002F*\" \\\n            --invariant-runs 512 \\\n            --invariant-depth 256 -vv\n\n      - name: Fork tests\n        run: |\n          forge test --match-path \"test\u002Ffork\u002F*\" \\\n            --fork-url ${{ secrets.ETH_RPC_URL }} -vvv\n        env:\n          ETH_RPC_URL: ${{ secrets.ETH_RPC_URL }}\n\n  gas:\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n      - uses: foundry-rs\u002Ffoundry-toolchain@v1\n\n      - name: Gas snapshot\n        run: forge snapshot\n\n      - name: Compare gas\n        run: forge snapshot --check --tolerance 2\n\n      - name: Upload snapshot\n        uses: actions\u002Fupload-artifact@v4\n        with:\n          name: gas-snapshot\n          path: .gas-snapshot\n\n  static-analysis:\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n\n      - name: Slither analysis\n        uses: crytic\u002Fslither-action@v0.4.0\n        with:\n          sarif: results.sarif\n          fail-on: medium\n\n      - name: Upload SARIF\n        uses: github\u002Fcodeql-action\u002Fupload-sarif@v3\n        with:\n          sarif_file: results.sarif\n\n      - name: Aderyn analysis\n        run: |\n          cargo install aderyn\n          aderyn . --output report.md\n\n      - name: Upload Aderyn report\n        uses: actions\u002Fupload-artifact@v4\n        with:\n          name: aderyn-report\n          path: report.md\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"gas-regression-tracking-with-forge-snapshot\">Gas Regression Tracking with forge snapshot\u003C\u002Fh2>\n\u003Cp>Gas regression is a critical metric for smart contracts. A 5% gas increase in a DEX router’s swap function costs real money at scale. Track it systematically:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\"># Generate baseline (commit to repo)\nforge snapshot &gt; .gas-snapshot\ngit add .gas-snapshot\ngit commit -m \"chore: update gas snapshot\"\n\n# In CI, compare against baseline\nforge snapshot --check .gas-snapshot --tolerance 2\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The \u003Ccode>--tolerance 2\u003C\u002Fcode> flag allows up to 2% gas increase before failing. For hot paths like MEV bot operations, set tolerance to 0%.\u003C\u002Fp>\n\u003Cp>For PR comments showing gas diffs, create a custom action:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yaml\">  gas-report:\n    runs-on: ubuntu-latest\n    if: github.event_name == 'pull_request'\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n      - uses: foundry-rs\u002Ffoundry-toolchain@v1\n\n      - name: Generate gas diff\n        run: |\n          forge snapshot --diff .gas-snapshot &gt; gas-diff.txt 2&gt;&amp;1 || true\n          echo \"## Gas Report\" &gt; comment.md\n          echo '```' &gt;&gt; comment.md\n          cat gas-diff.txt &gt;&gt; comment.md\n          echo '```' &gt;&gt; comment.md\n\n      - name: Post PR comment\n        uses: marocchino\u002Fsticky-pull-request-comment@v2\n        with:\n          path: comment.md\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"static-analysis-slither-and-aderyn\">Static Analysis: Slither and Aderyn\u003C\u002Fh2>\n\u003Ch3>Slither\u003C\u002Fh3>\n\u003Cp>Slither is the industry-standard static analyzer for Solidity. It detects vulnerability patterns like reentrancy, unchecked external calls, and access control issues:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">slither . --filter-paths \"test\u002F|script\u002F|lib\u002F\" \\\n  --exclude naming-convention,solc-version \\\n  --fail-on medium\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Common findings and how to handle them:\u003C\u002Fp>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Finding\u003C\u002Fth>\u003Cth>Severity\u003C\u002Fth>\u003Cth>Action\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Reentrancy\u003C\u002Ftd>\u003Ctd>High\u003C\u002Ftd>\u003Ctd>Fix immediately, use CEI pattern\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Unchecked return\u003C\u002Ftd>\u003Ctd>Medium\u003C\u002Ftd>\u003Ctd>Add return value check\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Naming convention\u003C\u002Ftd>\u003Ctd>Info\u003C\u002Ftd>\u003Ctd>Suppress with \u003Ccode>--exclude\u003C\u002Fcode>\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Unused state variable\u003C\u002Ftd>\u003Ctd>Low\u003C\u002Ftd>\u003Ctd>Remove or suppress\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>For Huff contracts, Slither cannot analyze the bytecode directly. Instead, analyze the Solidity interface contracts and integration tests that call the Huff contracts.\u003C\u002Fp>\n\u003Ch3>Aderyn\u003C\u002Fh3>\n\u003Cp>Aderyn is a Rust-based static analyzer that complements Slither with additional checks:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">aderyn . --output report.json --format json\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Aderyn is particularly good at catching gas optimization opportunities and detecting centralization risks.\u003C\u002Fp>\n\u003Ch2 id=\"deployment-checklists\">Deployment Checklists\u003C\u002Fh2>\n\u003Cp>Automate pre-deployment checks with a script:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F script\u002FDeployChecklist.s.sol\ncontract DeployChecklist is Script {\n    function run() external view {\n        \u002F\u002F 1. Verify compiler settings\n        require(block.chainid == 1, \"Wrong chain!\");\n\n        \u002F\u002F 2. Verify constructor args\n        address expectedOwner = vm.envAddress(\"OWNER\");\n        require(expectedOwner != address(0), \"Owner not set\");\n\n        \u002F\u002F 3. Verify all dependencies are deployed\n        require(\n            IWETH(WETH).totalSupply() &gt; 0,\n            \"WETH not deployed\"\n        );\n\n        console.log(\"All checks passed\");\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode class=\"language-bash\"># Dry run against mainnet fork\nforge script script\u002FDeployChecklist.s.sol \\\n  --fork-url $ETH_RPC_URL -vvv\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"automated-verification-on-etherscan\">Automated Verification on Etherscan\u003C\u002Fh2>\n\u003Cp>Post-deployment, automatically verify contracts on Etherscan so users can read the source:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">forge verify-contract \\\n  --chain mainnet \\\n  --num-of-optimizations 200 \\\n  --watch \\\n  --compiler-version v0.8.24 \\\n  --etherscan-api-key $ETHERSCAN_KEY \\\n  $CONTRACT_ADDRESS \\\n  src\u002FMyContract.sol:MyContract\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>For contracts with constructor arguments:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\"># Encode constructor args\ncast abi-encode \"constructor(address,uint256)\" $OWNER $INITIAL_SUPPLY\n\n# Pass encoded args to verify\nforge verify-contract \\\n  --constructor-args $(cast abi-encode \"constructor(address,uint256)\" $OWNER $INITIAL_SUPPLY) \\\n  $CONTRACT_ADDRESS \\\n  src\u002FMyContract.sol:MyContract\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Automate this in CI by adding a deployment job that triggers on tag pushes:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yaml\">  deploy-verify:\n    runs-on: ubuntu-latest\n    if: startsWith(github.ref, 'refs\u002Ftags\u002Fv')\n    needs: [test, gas, static-analysis]\n    environment: mainnet\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          submodules: recursive\n      - uses: foundry-rs\u002Ffoundry-toolchain@v1\n\n      - name: Deploy\n        run: |\n          forge script script\u002FDeploy.s.sol \\\n            --rpc-url ${{ secrets.ETH_RPC_URL }} \\\n            --broadcast \\\n            --verify \\\n            --etherscan-api-key ${{ secrets.ETHERSCAN_KEY }} \\\n            -vvv\n        env:\n          PRIVATE_KEY: ${{ secrets.DEPLOYER_KEY }}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"deployment-simulation\">Deployment Simulation\u003C\u002Fh2>\n\u003Cp>Before deploying to mainnet, simulate the entire deployment against a fork:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\"># Simulate deployment\nforge script script\u002FDeploy.s.sol \\\n  --fork-url $ETH_RPC_URL \\\n  --sender $DEPLOYER \\\n  -vvvv\n\n# If simulation passes, broadcast\nforge script script\u002FDeploy.s.sol \\\n  --rpc-url $ETH_RPC_URL \\\n  --broadcast \\\n  --slow \\\n  --verify\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The \u003Ccode>--slow\u003C\u002Fcode> flag submits transactions one at a time and waits for confirmation, which is safer for multi-step deployments.\u003C\u002Fp>\n\u003Ch2 id=\"monitoring-post-deployment\">Monitoring Post-Deployment\u003C\u002Fh2>\n\u003Cp>After deployment, set up automated monitoring:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yaml\">  post-deploy-check:\n    runs-on: ubuntu-latest\n    needs: deploy-verify\n    steps:\n      - name: Verify deployment\n        run: |\n          # Check contract is verified on Etherscan\n          STATUS=$(curl -s \"https:\u002F\u002Fapi.etherscan.io\u002Fapi?module=contract&amp;action=getabi&amp;address=$CONTRACT\" | jq -r '.status')\n          [ \"$STATUS\" = \"1\" ] || exit 1\n\n          # Check contract responds correctly\n          OWNER=$(cast call $CONTRACT \"owner()\" --rpc-url $RPC)\n          [ \"$OWNER\" = \"$EXPECTED_OWNER\" ] || exit 1\n\n          echo \"Deployment verified successfully\"\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"security-tooling-summary\">Security Tooling Summary\u003C\u002Fh2>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Tool\u003C\u002Fth>\u003Cth>Type\u003C\u002Fth>\u003Cth>Best For\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Slither\u003C\u002Ftd>\u003Ctd>Static analysis\u003C\u002Ftd>\u003Ctd>Vulnerability patterns, Solidity\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Aderyn\u003C\u002Ftd>\u003Ctd>Static analysis\u003C\u002Ftd>\u003Ctd>Gas, centralization risks\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Foundry Fuzz\u003C\u002Ftd>\u003Ctd>Dynamic testing\u003C\u002Ftd>\u003Ctd>Edge cases, boundary values\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Foundry Invariant\u003C\u002Ftd>\u003Ctd>Stateful fuzzing\u003C\u002Ftd>\u003Ctd>State-dependent bugs\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Echidna\u003C\u002Ftd>\u003Ctd>Fuzzer\u003C\u002Ftd>\u003Ctd>Property testing (alternative)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Mythril\u003C\u002Ftd>\u003Ctd>Symbolic execution\u003C\u002Ftd>\u003Ctd>Path exploration\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Certora\u003C\u002Ftd>\u003Ctd>Formal verification\u003C\u002Ftd>\u003Ctd>Mathematical proofs\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Ch2 id=\"conclusion\">Conclusion\u003C\u002Fh2>\n\u003Cp>A production-grade smart contract CI\u002FCD pipeline is fundamentally different from traditional software CI. Every stage serves as a safety gate before irreversible deployment. Gas snapshots catch performance regressions, static analyzers flag vulnerability patterns, fuzzers explore edge cases, and deployment simulations verify behavior against real state. The pipeline’s job is simple: make it harder to deploy a bug than to catch one.\u003C\u002Fp>\n","en","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:23.131592Z","CI\u002FCD for Smart Contracts — Testing, Gas Regression, and Safety","Build a production-grade CI\u002FCD pipeline for smart contracts with gas regression tracking, static analysis, and automated Etherscan verification.","smart contract ci cd pipeline",null,"index, follow",[22,27,31,35],{"id":23,"name":24,"slug":25,"created_at":26},"c0000000-0000-0000-0000-000000000012","DevOps","devops","2026-03-28T10:44:21.513630Z",{"id":28,"name":29,"slug":30,"created_at":26},"c0000000-0000-0000-0000-000000000016","EVM","evm",{"id":32,"name":33,"slug":34,"created_at":26},"c0000000-0000-0000-0000-000000000021","Foundry","foundry",{"id":36,"name":37,"slug":38,"created_at":26},"c0000000-0000-0000-0000-000000000013","Security","security","Blockchain",[41,48,54],{"id":42,"title":43,"slug":44,"excerpt":45,"locale":12,"category_name":46,"published_at":47},"d0200000-0000-0000-0000-000000000003","Why Bali Is Becoming Southeast Asia's Impact-Tech Hub in 2026","why-bali-becoming-southeast-asia-impact-tech-hub-2026","Bali ranks #16 among Southeast Asian startup ecosystems. With a growing concentration of Web3 builders, AI sustainability startups, and eco-travel tech companies, the island is carving a niche as the region's impact-tech capital.","Engineering","2026-03-28T10:44:37.748283Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":46,"published_at":53},"d0200000-0000-0000-0000-000000000002","ASEAN Data Protection Patchwork: A Developer's Compliance Checklist","asean-data-protection-patchwork-developer-compliance-checklist","Seven ASEAN countries now have comprehensive data protection laws, each with different consent models, localization requirements, and penalty structures. Here is a practical compliance checklist for developers building multi-country applications.","2026-03-28T10:44:37.374741Z",{"id":55,"title":56,"slug":57,"excerpt":58,"locale":12,"category_name":46,"published_at":59},"d0200000-0000-0000-0000-000000000001","Indonesia's $29 Billion Digital Transformation: Opportunities for Software Companies","indonesia-29-billion-digital-transformation-opportunities-software-companies","Indonesia's IT services market is projected to reach $29.03 billion in 2026, up from $24.37 billion in 2025. Cloud infrastructure, AI, e-commerce, and data centers are driving the fastest growth in Southeast Asia.","2026-03-28T10:44:37.349311Z",{"id":13,"name":61,"slug":62,"bio":63,"photo_url":19,"linkedin":19,"role":64,"created_at":65,"updated_at":65},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]