Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
0b9eec3
feat: add Commerce Escrow payment functionality and update Docker con…
rodrigopavezi Oct 21, 2025
796b5e5
refactor(payment-processor): update payment encoding to use individua…
rodrigopavezi Oct 22, 2025
3c16aae
refactor(payment-processor): simplify payment encoding by using param…
rodrigopavezi Oct 22, 2025
3afacad
refactor(payment-processor): enhance payment encoding by using utils.…
rodrigopavezi Oct 22, 2025
be390cc
refactor(smart-contracts): improve error handling and update commerce…
rodrigopavezi Oct 24, 2025
924f7f4
test(payment-processor, smart-contracts): enhance payment encoding te…
rodrigopavezi Oct 24, 2025
ec8b6a1
test(smart-contracts): enhance event assertions in ERC20CommerceEscro…
rodrigopavezi Oct 24, 2025
8cc4dac
test(smart-contracts): streamline event checks in ERC20CommerceEscrow…
rodrigopavezi Oct 24, 2025
8d273f2
feat(smart-contracts): add ERC20CommerceEscrowWrapper deployment and …
rodrigopavezi Nov 13, 2025
10f5f0c
refactor(payment-processor): simplify ERC20 allowance encoding by rem…
rodrigopavezi Nov 13, 2025
56e1afd
refactor(smart-contracts): optimize PaymentData struct for gas effici…
rodrigopavezi Nov 13, 2025
3a49f20
refactor(smart-contracts): enhance PaymentData struct with isActive f…
rodrigopavezi Nov 13, 2025
cd4fbec
refactor(smart-contracts): update ERC20CommerceEscrowWrapper and rela…
rodrigopavezi Nov 13, 2025
ddaf2b5
refactor(smart-contracts): update deployment script and artifact impo…
rodrigopavezi Nov 14, 2025
2156fc3
feat(smart-contracts): add fee validation and error handling in ERC20…
rodrigopavezi Nov 14, 2025
2bc7d83
refactor(smart-contracts): optimize ERC20CommerceEscrowWrapper for ga…
rodrigopavezi Nov 14, 2025
8e19768
refactor(smart-contracts): update Hardhat configuration for Solidity …
rodrigopavezi Nov 14, 2025
c30f884
refactor(payment-processor): update getPaymentData to derive isActive…
rodrigopavezi Nov 14, 2025
969ce5e
refactor(smart-contracts): update error handling in ERC20CommerceEscr…
rodrigopavezi Nov 18, 2025
c39a1ac
refactor(payment-processor): simplify ERC20 commerce escrow tests and…
rodrigopavezi Nov 18, 2025
6976984
refactor(smart-contracts): optimize PaymentData struct for clarity an…
rodrigopavezi Nov 18, 2025
71cb62c
refactor(smart-contracts): update error definitions and struct parame…
rodrigopavezi Nov 18, 2025
37fa07c
feat(smart-contracts): introduce ERC20CommerceEscrowWrapper and fee m…
rodrigopavezi Nov 18, 2025
1804263
Merge branch 'master' into feat/checkout-contracts
rodrigopavezi Nov 18, 2025
31c4fa0
chore(smart-contracts): update .gitignore and package.json for securi…
rodrigopavezi Nov 20, 2025
857861c
Merge branch 'feat/checkout-contracts' of https://github.com/RequestN…
rodrigopavezi Nov 20, 2025
947d9ba
Merge branch 'master' into feat/checkout-contracts
rodrigopavezi Nov 20, 2025
3d163bd
chore(workflows): enhance security workflow with dependency builds an…
rodrigopavezi Nov 20, 2025
3272134
Merge branch 'feat/checkout-contracts' of https://github.com/RequestN…
rodrigopavezi Nov 20, 2025
ebda4f0
chore(smart-contracts): add prebuild script for dependency builds
rodrigopavezi Nov 20, 2025
1254329
chore(workflows): update Echidna setup in security workflow
rodrigopavezi Nov 20, 2025
1b5e4c3
chore(workflows): fix Echidna wrapper script to include 'echidna' com…
rodrigopavezi Nov 20, 2025
325e5e3
chore(workflows): improve error handling in Echidna report processing
rodrigopavezi Nov 20, 2025
cca1eda
chore(workflows): improve error reporting in Echidna property validation
rodrigopavezi Nov 20, 2025
8f0dc6c
test(ERC20CommerceEscrowWrapper): enhance authorization payment test …
rodrigopavezi Nov 20, 2025
10d3458
fix(ERC20CommerceEscrowWrapper): update token approval process and si…
rodrigopavezi Nov 21, 2025
07d03b1
test(ERC20CommerceEscrowWrapper): update payment authorization test t…
rodrigopavezi Nov 21, 2025
8945643
refactor(MockAuthCaptureEscrow): reorder mappings for clarity in cont…
rodrigopavezi Nov 21, 2025
c151718
refactor(EchidnaERC20CommerceEscrowWrapper): enhance fuzzing harness …
rodrigopavezi Nov 21, 2025
ffdd73a
refactor(ERC20CommerceEscrowWrapper): update payment handling to rout…
rodrigopavezi Nov 21, 2025
48c3364
refactor(MockAuthCaptureEscrow): simplify refund logic and update com…
rodrigopavezi Nov 21, 2025
d5e1404
refactor(MockAuthCaptureEscrow): clarify refund logic and update comm…
rodrigopavezi Nov 21, 2025
8e93959
refactor(ERC20CommerceEscrowWrapper.test): initialize test counter to…
rodrigopavezi Nov 21, 2025
1d66120
refactor(ERC20CommerceEscrowWrapper): enhance token approval process …
rodrigopavezi Nov 21, 2025
81a79fd
fix(MockAuthCaptureEscrow): add check for capturable amount before re…
rodrigopavezi Nov 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
285 changes: 285 additions & 0 deletions .github/workflows/security-echidna.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
name: Security - Echidna Fuzzing

on:
pull_request:
branches:
- master
paths:
- 'packages/smart-contracts/src/contracts/**/*.sol'
- 'packages/smart-contracts/echidna.config.yml'
- '.github/workflows/security-echidna.yml'
schedule:
# Run thorough fuzzing nightly at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:
inputs:
mode:
description: 'Testing mode'
required: true
default: 'ci'
type: choice
options:
- ci
- quick
- thorough

permissions:
contents: read
pull-requests: write

jobs:
echidna-fuzzing:
name: Echidna Property-Based Fuzzing
runs-on: ubuntu-latest
timeout-minutes: 90

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'yarn'

- name: Install dependencies
working-directory: packages/smart-contracts
run: |
yarn install --frozen-lockfile

- name: Compile contracts
working-directory: packages/smart-contracts
run: |
yarn build:sol

- name: Setup Echidna
run: |
# Pull Echidna Docker image
docker pull trailofbits/echidna:latest

# Create a wrapper script to run echidna via docker
cat > /tmp/echidna << 'EOF'
#!/bin/bash
docker run --rm -v "$PWD":/src -w /src trailofbits/echidna:latest echidna "$@"
EOF

sudo mv /tmp/echidna /usr/local/bin/echidna
sudo chmod +x /usr/local/bin/echidna
echidna --version

- name: Restore corpus cache
uses: actions/cache@v4
with:
path: packages/smart-contracts/corpus
key: echidna-corpus-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
echidna-corpus-${{ github.ref_name }}-
echidna-corpus-master-

- name: Determine test mode
id: mode
run: |
if [ "${{ github.event_name }}" = "schedule" ]; then
echo "MODE=thorough" >> $GITHUB_OUTPUT
echo "TEST_LIMIT=500000" >> $GITHUB_OUTPUT
echo "TIMEOUT=3600" >> $GITHUB_OUTPUT
elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
MODE="${{ github.event.inputs.mode }}"
echo "MODE=$MODE" >> $GITHUB_OUTPUT
if [ "$MODE" = "thorough" ]; then
echo "TEST_LIMIT=500000" >> $GITHUB_OUTPUT
echo "TIMEOUT=3600" >> $GITHUB_OUTPUT
elif [ "$MODE" = "quick" ]; then
echo "TEST_LIMIT=100000" >> $GITHUB_OUTPUT
echo "TIMEOUT=300" >> $GITHUB_OUTPUT
else
echo "TEST_LIMIT=50000" >> $GITHUB_OUTPUT
echo "TIMEOUT=180" >> $GITHUB_OUTPUT
fi
else
# Default CI mode
echo "MODE=ci" >> $GITHUB_OUTPUT
echo "TEST_LIMIT=50000" >> $GITHUB_OUTPUT
echo "TIMEOUT=180" >> $GITHUB_OUTPUT
fi

- name: Run Echidna Fuzzing
id: echidna
working-directory: packages/smart-contracts
continue-on-error: true
run: |
mkdir -p reports/security

echo "Running Echidna in ${{ steps.mode.outputs.MODE }} mode..."
echo "Test limit: ${{ steps.mode.outputs.TEST_LIMIT }}"
echo "Timeout: ${{ steps.mode.outputs.TIMEOUT }}s"

echidna src/contracts/test/EchidnaERC20CommerceEscrowWrapper.sol \
--contract EchidnaERC20CommerceEscrowWrapper \
--config echidna.config.yml \
--test-limit ${{ steps.mode.outputs.TEST_LIMIT }} \
--timeout ${{ steps.mode.outputs.TIMEOUT }} \
--format text \
| tee reports/security/echidna-report.txt

ECHIDNA_EXIT=${PIPESTATUS[0]}

# Save coverage if available
if [ -f coverage.txt ]; then
mv coverage.txt reports/security/echidna-coverage.txt
fi

exit $ECHIDNA_EXIT

- name: Parse Echidna results
if: always()
id: parse
working-directory: packages/smart-contracts
run: |
# Count passed and failed properties
PASSED=$(grep -c "echidna.*: passed" reports/security/echidna-report.txt 2>/dev/null || echo "0")
FAILED=$(grep -c "echidna.*: failed" reports/security/echidna-report.txt 2>/dev/null || echo "0")

# Ensure variables are single line and numeric
PASSED=${PASSED##*$'\n'}
FAILED=${FAILED##*$'\n'}

TOTAL=$((PASSED + FAILED))

echo "PASSED=$PASSED" >> $GITHUB_OUTPUT
echo "FAILED=$FAILED" >> $GITHUB_OUTPUT
echo "TOTAL=$TOTAL" >> $GITHUB_OUTPUT

# Extract any counterexamples
if [ "$FAILED" -gt 0 ]; then
grep -A 10 "failed" reports/security/echidna-report.txt > reports/security/counterexamples.txt 2>/dev/null || true
fi

- name: Upload Echidna reports
if: always()
uses: actions/upload-artifact@v4
with:
name: echidna-reports-${{ steps.mode.outputs.MODE }}
path: |
packages/smart-contracts/reports/security/
packages/smart-contracts/corpus/
retention-days: 90

- name: Comment on PR
if: github.event_name == 'pull_request' && always()
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const passed = '${{ steps.parse.outputs.PASSED }}';
const failed = '${{ steps.parse.outputs.FAILED }}';
const total = '${{ steps.parse.outputs.TOTAL }}';
const mode = '${{ steps.mode.outputs.MODE }}';
const testLimit = '${{ steps.mode.outputs.TEST_LIMIT }}';
const status = '${{ steps.echidna.outcome }}';

const statusEmoji = status === 'success' ? '✅' : '❌';
const passRate = total > 0 ? ((passed / total) * 100).toFixed(1) : '0';

let body = `## ${statusEmoji} Echidna Fuzzing Results

**Mode:** ${mode} (${testLimit} test sequences)
**Status:** ${status === 'success' ? 'All Properties Passed' : 'Property Violations Found'}

### Property Test Results

| Status | Count |
|--------|-------|
| ✅ Passed | ${passed} |
| ❌ Failed | ${failed} |
| **Total** | **${total}** |
| **Pass Rate** | **${passRate}%** |

`;

if (failed > 0) {
body += `### ⚠️ Invariant Violations Detected

Echidna found sequences of transactions that violate defined invariants.
This indicates potential security issues or logic errors.

**Action Required:**
1. Download the artifacts to see counterexamples
2. Review the failing properties
3. Fix the contract or adjust the properties
4. Re-run the fuzzing campaign

`;
}

body += `📄 Full report and corpus available in workflow artifacts.

<details>
<summary>ℹ️ About Echidna Fuzzing</summary>

Echidna is a property-based fuzzer that generates random sequences of transactions
to test invariants (properties that should always hold true).

**Properties tested:**
- Fee calculation bounds
- Access control enforcement
- Amount constraints
- No duplicate payments
- Zero address validation
- Integer overflow protection

</details>`;

github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});

- name: Create issue for nightly failures
if: github.event_name == 'schedule' && steps.echidna.outcome == 'failure'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const passed = '${{ steps.parse.outputs.PASSED }}';
const failed = '${{ steps.parse.outputs.FAILED }}';

github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `🔴 Echidna Nightly Fuzzing Failed - ${new Date().toISOString().split('T')[0]}`,
body: `## Echidna Nightly Fuzzing Campaign Failed

**Date:** ${new Date().toISOString()}
**Branch:** ${context.ref}
**Commit:** ${context.sha}

### Results
- ✅ Passed: ${passed}
- ❌ Failed: ${failed}

### Details
The thorough nightly fuzzing campaign found property violations.

**Action Items:**
1. Review the [workflow run](${context.payload.repository.html_url}/actions/runs/${context.runId})
2. Download artifacts to examine counterexamples
3. Investigate and fix violations
4. Re-run fuzzing to verify fix

/cc @RequestNetwork/security-team`,
labels: ['security', 'fuzzing', 'high-priority']
});

- name: Fail on property violations
if: steps.parse.outputs.FAILED != '0' && steps.parse.outputs.FAILED != ''
run: |
echo "::error::Echidna found property violations. Check the reports for counterexamples."
echo "::error::Failed properties: ${{ steps.parse.outputs.FAILED }}"
echo "::error::Passed properties: ${{ steps.parse.outputs.PASSED }}"
exit 1
Loading
Loading