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#
# 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 devProject 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#
| Mode | Use Case | Command |
|---|---|---|
| Mock | Frontend work without contracts | Set NEXT_PUBLIC_MOCK_MODE=true in apps/web/.env.local |
| Local | Full stack with local GenLayer node | pnpm dev:local |
| Testnet | Integration testing on Base Sepolia | Configure .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.
pnpm test:directThese 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:
cd contracts/evm && forge test
# With verbose output
cd contracts/evm && forge test -vvvGenLayer Simulator Tests#
Requires a running GenLayer node at localhost:4000:
# Single smoke test
pnpm test:sim
# Full suite
pnpm test:sim:allFull Contract CI#
Runs lint, direct tests, and simulator tests in sequence:
pnpm test:icTypeScript Tests#
pnpm test:unit # Unit tests
pnpm test:e2e # End-to-end testsWriting Tests#
GenLayer Contract Tests#
GenLayer tests use the gltest framework with pytest. The test fixtures are defined in tests/direct/conftest.py.
# 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_registryfixture for DEV MODE (zero bridge_sender) - Use
prod_bounty_registry+ mock helpers for production mode - Set
direct_vm.senderbefore 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:
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:
pnpm format # Auto-fix formatting
pnpm format:check # Check without fixingLinting#
ESLint is configured per-package. Run linting with:
pnpm lint # Check for issues
pnpm lint:fix # Auto-fix where possibleGenLayer contracts have a separate linter:
pnpm lint:genlayerCommit Messages#
Use Conventional Commits:
| Prefix | Use 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 referencePull Request Process#
- Fork the repository and create a feature branch from
main - Implement your changes following the code style guidelines
- Write tests for new features (required) and bug fixes (encouraged)
- Run checks locally before pushing:
Bash
pnpm lint pnpm typecheck pnpm test:direct cd contracts/evm && forge test - Push your branch and open a PR against
main - 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:
# In apps/web/.env.local
NEXT_PUBLIC_MOCK_MODE=trueMock 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:
pipx install --force genlayer-testing-suiteUseful Commands#
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!