MergeProof

Contributing to Mergeproof#

Welcome! Mergeproof is a staked PR review protocol built on GenLayer + Base (EVM). We appreciate contributions of all kinds — bug fixes, features, documentation, and test coverage.

Prerequisites#

Before you start, make sure you have the following installed:

  • Node.js >= 20.0.0
  • pnpm >= 9.0.0 (corepack enable && corepack prepare pnpm@9.15.0)
  • Python 3.10+ (for GenLayer contract tests)
  • Foundry (installation guide)
  • Docker (for GenLayer simulator mode)

Getting Started#

Bash
# Clone the repository
git clone https://github.com/genlayerlabs/mergeproof.git
cd mergeproof

# Install dependencies
pnpm install

# Build all packages
pnpm build

# Start development servers
pnpm dev

Project Structure#

Mergeproof is a pnpm monorepo managed by Turborepo:

mergeproof/
├── apps/
│   ├── web/             # Next.js dashboard
│   ├── cli/             # TypeScript CLI
│   └── relay/           # Bridge relay service
├── contracts/
│   ├── genlayer/        # GenLayer intelligent contracts (Python)
│   └── evm/             # Solidity contracts (Foundry)
├── packages/
│   ├── core/            # Shared logic and types
│   ├── contracts/       # Contract ABIs and addresses
│   └── ui/              # Shared UI components
├── tests/
│   ├── direct/          # GenLayer direct-mode tests (fast, in-memory)
│   ├── intelligent_contracts/  # GenLayer simulator tests
│   └── e2e/             # End-to-end tests
└── docs/                # Documentation

Development Modes#

ModeUse CaseCommand
MockFrontend work without contractsSet NEXT_PUBLIC_MOCK_MODE=true in apps/web/.env.local
LocalFull stack with local GenLayer nodepnpm dev:local
TestnetIntegration testing on Base SepoliaConfigure .env with testnet RPC URLs

Mock mode serves synthetic data from apps/web/src/lib/api.ts — ideal for UI development without running any backend services.

Running Tests#

GenLayer Contract Tests (Direct Mode)#

Fast, in-memory tests that run contracts directly in Python without the simulator. Takes about 4 seconds.

Bash
pnpm test:direct

These tests use bridge_sender=zero_address (DEV MODE) to skip GitHub verification and RPC stake checks.

EVM Contract Tests (Foundry)#

Solidity tests using Foundry's forge:

Bash
cd contracts/evm && forge test

# With verbose output
cd contracts/evm && forge test -vvv

GenLayer Simulator Tests#

Requires a running GenLayer node at localhost:4000:

Bash
# Single smoke test
pnpm test:sim

# Full suite
pnpm test:sim:all

Full Contract CI#

Runs lint, direct tests, and simulator tests in sequence:

Bash
pnpm test:ic

TypeScript Tests#

Bash
pnpm test:unit    # Unit tests
pnpm test:e2e     # End-to-end tests

Writing Tests#

GenLayer Contract Tests#

GenLayer tests use the gltest framework with pytest. The test fixtures are defined in tests/direct/conftest.py.

Python
# Import fixtures from gltest
from gltest.direct.pytest_plugin import (
    direct_vm, direct_deploy, direct_alice, direct_bob,
)

class TestMyFeature:
    def test_something(self, dev_bounty_registry, direct_vm, direct_alice):
        """Use dev_bounty_registry for DEV MODE (skips external calls)."""
        direct_vm.sender = direct_alice
        dev_bounty_registry.dev_register_identity("alice_github")

        result = dev_bounty_registry.some_method()
        assert result == expected_value

    def test_revert(self, dev_bounty_registry, direct_vm, direct_alice):
        """Test expected reverts with direct_vm.expect_revert."""
        direct_vm.sender = direct_alice

        with direct_vm.expect_revert("Expected error message"):
            dev_bounty_registry.invalid_action()

Key patterns:

  • Use dev_bounty_registry fixture for DEV MODE (zero bridge_sender)
  • Use prod_bounty_registry + mock helpers for production mode
  • Set direct_vm.sender before each call to simulate different users
  • Use direct_vm.expect_revert("message") for revert assertions
  • Mock external calls with helpers like mock_github_user(), mock_rpc_stake()

EVM Contract Tests (Foundry)#

Solidity tests follow standard Foundry patterns with forge-std:

Solidity
import {Test} from "forge-std/Test.sol";
import {Escrow} from "../src/Escrow.sol";

contract MyTest is Test {
    Escrow public escrow;

    function setUp() public {
        // Deploy contracts and configure state
        escrow = new Escrow(treasury, owner);
    }

    function test_Something() public {
        vm.prank(userAddress);   // Set msg.sender for next call
        escrow.someFunction();

        assertEq(escrow.value(), expected);
    }

    function test_Reverts() public {
        vm.expectRevert(Escrow.CustomError.selector);
        escrow.invalidAction();
    }

    // Fuzz tests
    function testFuzz_Deposit(uint256 amount) public {
        vm.assume(amount > 0 && amount <= 100_000_000 * 1e6);
        // ...
    }
}

Code Style#

Formatting#

The project uses Prettier for TypeScript/JavaScript formatting and shares a config from @mergeproof/prettier-config. Run formatting with:

Bash
pnpm format          # Auto-fix formatting
pnpm format:check    # Check without fixing

Linting#

ESLint is configured per-package. Run linting with:

Bash
pnpm lint            # Check for issues
pnpm lint:fix        # Auto-fix where possible

GenLayer contracts have a separate linter:

Bash
pnpm lint:genlayer

Commit Messages#

Use Conventional Commits:

PrefixUse For
feat:New features
fix:Bug fixes
chore:Maintenance, deps, config
test:Adding or updating tests
docs:Documentation changes
refactor:Code restructuring without behavior change

Scope is optional but encouraged:

feat(contracts): add attestation pool to BountyRegistry
fix(web): align ReviewCTA sections
test(evm): add fuzz tests for deposit amounts
docs: update CLI reference

Pull Request Process#

  1. Fork the repository and create a feature branch from main
  2. Implement your changes following the code style guidelines
  3. Write tests for new features (required) and bug fixes (encouraged)
  4. Run checks locally before pushing:
    Bash
    pnpm lint
    pnpm typecheck
    pnpm test:direct
    cd contracts/evm && forge test
  5. Push your branch and open a PR against main
  6. Wait for CI — all checks must pass before merge

CI Pipeline#

The CI runs automatically on PRs to main:

  • Lint & typecheck
  • Build all packages
  • TypeScript unit tests
  • EVM/Foundry tests
  • GenLayer tests

Development Tips#

Frontend Mock Mode#

For UI work without contracts or backend:

Bash
# In apps/web/.env.local
NEXT_PUBLIC_MOCK_MODE=true

Mock data lives in apps/web/src/lib/api.ts. Update it to simulate different states.

Contract Dev Mode#

GenLayer contracts have a built-in DEV MODE activated when bridge_sender is the zero address. This:

  • Skips GitHub API verification
  • Skips RPC stake verification on Base
  • Enables dev_register_identity() for testing without GitHub OAuth
  • Allows mock data for PRs and issues

GenLayer Test Framework#

If gltest.direct imports fail, reinstall the testing suite:

Bash
pipx install --force genlayer-testing-suite

Useful Commands#

Bash
pnpm dev              # Start all dev servers
pnpm dev:local        # Full local stack (GenLayer + services)
pnpm build            # Build all packages
pnpm clean            # Remove all build artifacts and node_modules
pnpm deploy:genlayer  # Deploy GenLayer contracts
pnpm test:contracts   # Run all contract tests (GenLayer + EVM)

Getting Help#

  • Read the full specification: docs/SPEC.md
  • Check the architecture overview: docs/ARCHITECTURE.md
  • Open an issue for bugs or feature requests
  • Ask questions in discussions

Thank you for contributing!