Skip to content

Latest commit

 

History

History
661 lines (450 loc) · 15.1 KB

File metadata and controls

661 lines (450 loc) · 15.1 KB

Foundry and Makefile Guide for Liquidity Bridge Contract

This guide explains how to use Foundry and the Makefile for deploying, upgrading, and managing the Liquidity Bridge Contract across different networks.

Table of Contents

  1. Prerequisites
  2. Environment Setup
  3. Foundry Basics
  4. Makefile Overview
  5. Deployment Commands
  6. Network Configuration
  7. Fork Testing
  8. Safety Features
  9. Troubleshooting
  10. Examples

Prerequisites

Required Software

  • Foundry: Install from getfoundry.sh
  • Git: For version control
  • Node.js: For additional dependencies

Install Foundry

curl -L https://foundry.paradigm.xyz | bash
foundryup

Verify Installation

forge --version
cast --version
anvil --version

Environment Setup

1. Clone the Repository

git clone <repository-url>
cd liquidity-bridge-contract

2. Install Dependencies

# Install Foundry dependencies
forge install

# Install Node.js dependencies (if any)
npm install

3. Environment Configuration

Copy the example environment file and configure it:

cp example.env .env

Edit .env with your configuration:

# RPC URLs
MAINNET_RPC_URL=https://public-node.rsk.co
TESTNET_RPC_URL=https://public-node.testnet.rsk.co
REGTEST_RPC_URL=http://localhost:4444

# Private Keys (NEVER commit these!)
MAINNET_SIGNER_PRIVATE_KEY=your_mainnet_private_key
TESTNET_SIGNER_PRIVATE_KEY=your_testnet_private_key
DEV_SIGNER_PRIVATE_KEY=your_dev_private_key

# Existing contract addresses (for upgrades)
EXISTING_PROXY_MAINNET=0x...
EXISTING_ADMIN_MAINNET=0x...
EXISTING_PROXY_TESTNET=0x...
EXISTING_ADMIN_TESTNET=0x...

# Multisig configuration
MULTISIG_ADDRESS_MAINNET=0x...
MULTISIG_OWNER_1_MAINNET=0x...
# ... add more owners as needed

Foundry Basics

Key Foundry Commands

forge build

Compile all contracts:

forge build

forge test

Run tests:

forge test
forge test --gas-report  # With gas reporting

forge script

Execute deployment scripts:

forge script <script_path> --rpc-url <url> --private-key <key> --broadcast

forge verify-contract

Verify contracts on block explorers:

forge verify-contract <address> <contract_name> --chain-id <id> --etherscan-api-key <key>

Foundry Configuration (foundry.toml)

The project uses a custom foundry.toml configuration:

[profile.default]
src = "src"
test = "test"
out = "out"
cache_path = "cache"
solc_version = "0.8.25"
optimizer = true
optimizer_runs = 1

[rpc_endpoints]
rskRegtest = "${REGTEST_RPC_URL}"
rskTestnet = "${TESTNET_RPC_URL}"
rskMainnet = "${MAINNET_RPC_URL}"

Makefile Overview

The Makefile provides a convenient interface for all Foundry operations with built-in safety features.

Key Features

  • Network Support: Mainnet, Testnet, Dev environments
  • Fork Testing: Test against forked networks
  • Safety Validation: Environment checks and mainnet confirmations
  • Simulation vs Deployment: Separate commands for testing and actual deployment

Basic Usage

make <target> [NETWORK=<network>] [FORK_BLOCK=<block>] [VERIFY=<true|false>]

Deployment Commands

Simulation Commands (Safe Testing)

These commands simulate deployments without broadcasting transactions:

# Deploy LiquidityBridgeContract (simulation)
make deploy-lbc NETWORK=rskTestnet

# Upgrade to V2 (simulation)
make upgrade-lbc NETWORK=rskTestnet

# Transfer ownership (simulation)
make change-owner NETWORK=rskTestnet

# High gas deployment (simulation)
make deploy-lbc-high-gas NETWORK=rskTestnet

Actual Deployment Commands

These commands broadcast real transactions:

# Deploy LiquidityBridgeContract (actual)
make deploy-lbc-broadcast NETWORK=rskTestnet

# Upgrade to V2 (actual)
make upgrade-lbc-broadcast NETWORK=rskTestnet

# Transfer ownership (actual)
make change-owner-broadcast NETWORK=rskTestnet

# High gas deployment (actual)
make deploy-lbc-high-gas-broadcast NETWORK=rskTestnet

Safe Deployment Commands

These include additional validation:

# Safe deployment with validation
make safe-deploy-lbc-broadcast NETWORK=rskMainnet

# Safe upgrade with validation
make safe-upgrade-lbc-broadcast NETWORK=rskMainnet

# Safe ownership transfer with validation
make safe-change-owner-broadcast NETWORK=rskMainnet

Network Configuration

Supported Networks

Network Chain ID RPC URL Description
rskMainnet 30 RSK Mainnet Production network
rskTestnet 31 RSK Testnet Test network
rskDevelopment 31 RSK Testnet Development addresses (same chain as testnet)
rskRegtest 33 RSK Regtest Local regtest node

Network-Specific Commands

# Mainnet operations
make deploy-lbc NETWORK=rskMainnet
make upgrade-lbc-broadcast NETWORK=rskMainnet

# Testnet operations
make deploy-lbc NETWORK=rskTestnet
make change-owner-broadcast NETWORK=rskTestnet

# Dev operations
make dev-deploy
make dev-deploy-broadcast

Fork Testing

Fork testing allows you to test against real network state without using real funds.

Fork Commands

# Testnet fork simulation
make testnet-fork-deploy

# Testnet fork actual deployment
make testnet-fork-deploy-broadcast

# Mainnet fork simulation
make mainnet-fork-deploy

# Mainnet fork actual deployment
make mainnet-fork-deploy-broadcast

Fork Configuration

# Specify fork block
make deploy-lbc NETWORK=rskTestnet FORK_BLOCK=6020639

# Use latest block
make deploy-lbc NETWORK=rskMainnet FORK_BLOCK=latest

Safety Features

Environment Validation

The Makefile includes built-in safety checks:

# Check environment configuration
make check-env NETWORK=rskTestnet

# Validate deployment prerequisites
make validate-deploy NETWORK=rskMainnet

Mainnet Protection

Mainnet deployments require explicit confirmation:

# This will prompt for confirmation
make safe-deploy-lbc-broadcast NETWORK=rskMainnet

Gas Management

# Default gas limit (10M)
make deploy-lbc NETWORK=rskTestnet

# High gas limit (15M)
make deploy-lbc-high-gas NETWORK=rskTestnet

# Custom gas limit
make deploy-lbc NETWORK=rskTestnet GAS_LIMIT=20000000

Utility Commands

Contract Information

# Get contract versions
make get-versions

# Get BTC block height
make get-btc-height

Development Commands

# Build contracts
make build

# Run tests
make test

# Run tests with coverage
make coverage

# Clean build artifacts
make clean

# Install dependencies
make install

# Update dependencies
make update

Documentation

# Generate documentation
make docs

# Show help
make help

Troubleshooting

Common Issues

1. Gas Price Errors

Error: invalid value 'auto' for '--gas-price'

Solution: The Makefile now uses --legacy flag and proper gas price handling.

2. Out of Gas Errors

Error: execution reverted: EvmError: OutOfGas

Solution: Use high gas commands:

make deploy-lbc-high-gas NETWORK=rskTestnet

3. EIP-1559 Fee Errors

Error: Failed to get EIP-1559 fees

Solution: The Makefile automatically uses --legacy flag.

4. Missing Dependencies

Error: No such file or directory: forge-std/Script.sol

Solution: Install dependencies:

make install
# or
forge install

5. Nonce Errors

Error: transaction nonce too low

Solution: This is expected when using a private key that has already been used. Use a fresh private key for testing.

Environment Issues

Private Key Not Set

# Check if private key is set
make check-env NETWORK=rskTestnet

# Set in .env file
TESTNET_SIGNER_PRIVATE_KEY=your_private_key

RPC URL Issues

# Test RPC connection
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' https://public-node.testnet.rsk.co

Examples

Complete Deployment Workflow

# 1. Setup environment
cp example.env .env
# Edit .env with your configuration

# 2. Install dependencies
make install

# 3. Build contracts
make build

# 4. Test deployment (simulation)
make deploy-lbc NETWORK=rskTestnet

# 5. Check environment
make check-env NETWORK=rskTestnet

# 6. Actual deployment
make deploy-lbc-broadcast NETWORK=rskTestnet

# 7. Verify deployment
make get-versions

Fork Testing Workflow

# 1. Test on forked testnet
make testnet-fork-deploy

# 2. Test on forked mainnet
make mainnet-fork-deploy

# 3. Deploy on forked testnet
make testnet-fork-deploy-broadcast

Upgrade Workflow

# 1. Test upgrade (simulation)
make upgrade-lbc NETWORK=rskTestnet

# 2. Check environment
make check-env NETWORK=rskTestnet

# 3. Perform upgrade
make upgrade-lbc-broadcast NETWORK=rskTestnet

# 4. Verify upgrade
make get-versions

Ownership Transfer Workflow

# 1. Test ownership transfer (simulation)
make change-owner NETWORK=rskTestnet

# 2. Validate multisig configuration
make check-env NETWORK=rskTestnet

# 3. Transfer ownership
make change-owner-broadcast NETWORK=rskTestnet

Best Practices

1. Always Test First

# Always run simulation before actual deployment
make deploy-lbc NETWORK=rskTestnet
make deploy-lbc-broadcast NETWORK=rskTestnet

2. Use Fork Testing

# Test against real network state
make testnet-fork-deploy
make mainnet-fork-deploy

3. Validate Environment

# Check configuration before deployment
make check-env NETWORK=rskMainnet

4. Use Safe Commands for Mainnet

# Safe commands include additional validation
make safe-deploy-lbc-broadcast NETWORK=rskMainnet

5. Monitor Gas Usage

# Use gas reporting
make gas-report

# Use high gas for complex deployments
make deploy-lbc-high-gas NETWORK=rskTestnet

6. Keep Dependencies Updated

# Regular updates
make update

Formal Verification (Halmos)

What It Adds

The project uses Halmos for symbolic testing, which complements existing fuzz and invariant tests. While fuzzing explores random inputs and invariant tests check properties after random sequences of calls, Halmos converts test assertions into SMT constraints and proves they hold for all possible inputs within bounded execution. If Halmos finds no counterexample, the property is mathematically proven correct within the explored bounds.

The property catalog — what each proof actually claims, its assumptions, and why it matters — lives in FORMAL_VERIFICATION.md. Treat that document as the source of truth for the specification; the Solidity in test/formal/ is one encoding of those claims.

Prerequisites

The recommended one-command setup creates a project-local virtualenv at .venv/ with the pinned Halmos version:

make python-setup
source .venv/bin/activate

The setup script (scripts/setup-python.sh) prefers uv when available — it can fetch its own Python 3.12 if the system doesn't have one — and falls back to a system python3.12 or python3.11. Re-running is safe; the existing venv is upgraded in place.

The Halmos pin lives at the top of scripts/setup-python.sh (HALMOS_VERSION). When bumping it, update the matching pin in .github/workflows/formal.yml and the lib/halmos-cheatcodes submodule in lockstep (see below).

Note: Do not add a root-level requirements.txtcrytic/slither-action auto-installs it in CI inside a Python 3.9 container. Python tooling is not installed by npm ci; run make python-setup once after cloning (or when the Halmos pin changes). Optional git hooks live in .pre-commit-config.yaml; install with pip install pre-commit && pre-commit install if you want them.

The halmos-cheatcodes Foundry library is tracked as a git submodule at lib/halmos-cheatcodes/, pinned to a specific upstream commit of a16z/halmos-cheatcodes. After cloning the repo run:

git submodule update --init --recursive
# or, equivalently:
forge install

To bump the cheatcodes version, update the submodule commit in lockstep with the Halmos Python pin so both halves of the toolchain stay compatible:

cd lib/halmos-cheatcodes
git fetch origin
git checkout <new-commit-or-tag>
cd ../..
git add lib/halmos-cheatcodes

Writing Formal Tests

Formal tests live in test/formal/ and follow Halmos conventions:

  • Function prefix: Use check_ instead of test or testFuzz_. Halmos treats parameters as symbolic (all possible values), not random.
  • Base contract: Extend FormalBase (in test/formal/FormalBase.sol) which provides the deployed CollateralManagement system and SymTest helpers.
  • Assertions: Use assert() for properties Halmos will prove. Use vm.assume() to constrain symbolic inputs.
  • File naming: <Contract>.check.t.sol (the .check. distinguishes formal from unit/fuzz tests).

Example:

function check_SlashConservation(
  uint256 collateral,
  uint256 penaltyFee
) public {
  vm.assume(collateral > 0 && collateral <= 100 ether);
  vm.assume(penaltyFee > 0 && penaltyFee <= 100 ether);
  // ... setup and call ...
  assert(rewardDelta + penaltyDelta == effectivePenalty);
}

Running Formal Tests

# Run all formal verification tests
make test-formal

# Or via npm
npm run test:formal

Halmos runs are significantly slower than Foundry tests (minutes rather than seconds) because they solve SMT constraints. CI runs formal tests in a dedicated workflow (.github/workflows/formal.yml).

When to Run

Run formal verification (npm run test:formal) when:

  • Arithmetic logic changes (slashing, rewards, collateral accounting)
  • Access control or state-transition guards change
  • New invariant properties are added

Security Considerations

Private Key Management

  • NEVER commit private keys to version control
  • Use environment variables for all private keys
  • Consider using hardware wallets for mainnet operations

Network Selection

  • Always double-check the network before deployment
  • Use simulation commands first
  • Use safe commands for mainnet

Gas Management

  • Monitor gas prices and limits
  • Use appropriate gas limits for complex operations
  • Consider gas price fluctuations

Verification

  • Verify all contracts after deployment
  • Use make get-versions to confirm deployments
  • Monitor contract interactions

Support

For issues and questions:

  1. Check the troubleshooting section
  2. Review the Foundry documentation
  3. Check the project's README.md
  4. Open an issue in the project repository

Remember: Always test thoroughly before deploying to mainnet, and never use real private keys in development environments.