Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ alloy = { version = "1.0", features = ["default", "arbitrary", "k256", "serde",
alloy-chains = "0.2"
# derive feature is not exposed via `alloy`, thus has to explicitly declare here
alloy-rlp = { version = "0.3.12", features = ["derive"] }
anvil = "0.3.2"
anyhow = "1.0.89"
arbitrary = { version = "1", features = ["derive"] }
arbtest = "0.3.2"
Expand Down
6 changes: 2 additions & 4 deletions contracts/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
cache/
out/

# Ignores development broadcast logs
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/
# Ignore broadcast logs
broadcast

# Docs
docs/
Expand Down
143 changes: 143 additions & 0 deletions contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Timeboost Smart Contracts

This directory contains the smart contracts that power the decentralized Timeboost protocol. These contracts run on Ethereum-compatible blockchains and provide the foundation for secure, decentralized time synchronization.

## Background
Smart contracts are executable code, deployed on blockchains that
can be read from / written to anyone with an internet connection.
Transaction data and smart contract storage is public and can be
accessed in blockchain explorers. In decentralized Timeboost,
smart contracts are used to allow anyone to interact with various
of the protocol. This readme is directed at developers who are
contributing to or making use of this decentralized timeboost
implementation.

## What Are These Contracts For?

Timeboost needs a way to coordinate cryptographic keys and committee members across a decentralized network. These smart contracts provide:

- **Key Management**: Store and manage encryption keys for the protocol
- **Committee Coordination**: Track which nodes are part of the consensus committee
- **Access Control**: Ensure only authorized parties can update critical protocol parameters
- **Transparency**: All changes are recorded on-chain for public verification

These contracts act as the "coordination layer" that allows the Timeboost network to operate without a central authority.

## Handling Upgradeability

### The Upgrade Problem
Once deployed, smart contracts can't be changed. To solve this, we use a proxy solution that performs functionally as upgradeable contracts.

### The Proxy Solution
We use a "proxy pattern" that works like this:

1. **Users always interact with the proxy** - This address never changes
2. **The proxy points to an implementation** - This can be updated
3. **When you upgrade** - Just point the proxy to a new implementation
4. **All data stays safe** - Storage is preserved across upgrades

Think of it like changing the engine in a car - the car (proxy) stays the same, but you can swap out the engine (implementation) for a better one.

### Our Architecture
```
User → Proxy Contract → Implementation Contract
Storage (persistent)
```

## The Contracts

### KeyManager - The Main Contract

**What it stores:**
- **Encryption keys** - The cryptographic keys used by the protocol
- **Committee members** - Who's currently in the consensus committee
- **Manager address** - Who can update the contract

**What it does:**
- **Sets committees** - Updates which nodes are part of the network
- **Manages keys** - Stores the threshold encryption key
- **Controls access** - Only the manager can make changes
- **Logs everything** - All changes are recorded as events

**Key functions:**
- `setNextCommittee()` - Add a new committee with future members
- `currentCommitteeId()` - Find which committee is active right now
- `getCommitteeById()` - Get details about a specific committee
- `setThresholdEncryptionKey()` - Set the encryption key for the protocol

### ERC1967Proxy - The Upgrade Mechanism
This is the "shell" that makes upgrades possible:

- **Never changes** - Users always interact with this address
- **Delegates calls** - Forwards requests to the current implementation
- **Preserves data** - All storage survives upgrades
- **SecOps Precautions** - it's important to call the initialize methods during deploys and upgrades so that those transactions aren't front-run

## Getting Started

### Prerequisites
- **Foundry** - For building and testing contracts

### Building the Contracts
```bash
# Build all contracts
just build-contracts

# Or use forge directly
forge build
```

### Testing
```bash
# Run all tests
just test-contracts

# Run with detailed output
forge test --vvv

# Run specific test
forge test --match-test test_setThresholdEncryptionKey
```

### Integration Testing
For testing contract interactions from Rust code, see the [timeboost-contract README](../timeboost-contract/README.md).

## Deployment
You can deploy a local anvil network (as done in the test), a fork of a real network, a testnet network (e.g. Ethereum Sepolia) or a mainnet (e.g. Ethereum Mainnet).

### Quick Start (Local Testing)
```bash
# 1. Start a local blockchain
anvil

# 2. Deploy the contracts
cd script
cp env.example .env
# Edit .env with your values
./deploy.sh
```

**📋 For detailed deployment instructions, see the [deployment script README](script/README.md)**

## Security

### Current Status
- **ERC1967Proxy** - Audited by OpenZeppelin, widely used
- **KeyManager** - Not yet audited (audit planned)

### Security Considerations
- **Manager privileges** - The manager can update committees and keys
- **Upgrade authority** - Only the contract owner can upgrade
- **Committee validation** - Contracts validate committee transitions
- **Event logging** - All changes are logged onchain for transparency

### Best Practices
- **Use multisig wallets** - Don't use single-key wallets for manager/owner
- **Test thoroughly** - Always test on testnets first
- **Monitor events** - Watch for unexpected contract changes
- **Keep keys secure** - Store private keys and mnemonics safely

## Getting Help
- Check the [deployment script README](script/README.md) for deployment issues
- Review the [timeboost-contract README](../timeboost-contract/README.md) for integration questions
31 changes: 31 additions & 0 deletions contracts/env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Timeboost Contract Deployment Configuration
# Copy this file to .env and fill in your actual values
# DO NOT commit .env files to version control

# Manager address for the KeyManager contract
# This should be the address that will manage the KeyManager contract
# Typically a multisig wallet or governance contract address
# Example: MANAGER_ADDRESS=0x1234567890123456789012345678901234567890
MANAGER_ADDRESS=

# RPC endpoint for the target network
# For local development: http://localhost:8545 (Anvil)
# For testnets: https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY
# For mainnet: https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
RPC_URL=

# Deployment Account Mnemonic and account index
# Your 12 or 24 word BIP39 mnemonic phrase for the deployment account
# This account must have enough ETH to pay for gas fees
# Example: MNEMONIC="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
MNEMONIC=

# Which account to use from the mnemonic (0 = first account, 1 = second, etc.)
# Example: ACCOUNT_INDEX=0
ACCOUNT_INDEX=

# Etherscan API key for contract verification (optional)
# Get one at: https://etherscan.io/apis
# This is used to verify your contracts on Etherscan after deployment
# Example: ETHERSCAN_API_KEY=YourApiKeyToken
ETHERSCAN_API_KEY=
47 changes: 47 additions & 0 deletions contracts/script/DeployKeyManager.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script, console} from "forge-std/Script.sol";
import {KeyManager} from "../src/KeyManager.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

/// @title DeployKeyManager
/// @notice Simple script to deploy KeyManager implementation and proxy, then initialize
contract DeployKeyManager is Script {
function run() external returns (address, address) {
// Get the manager address from environment variable or use sender as fallback
address manager = vm.envOr("MANAGER_ADDRESS", msg.sender);

vm.startBroadcast();

// Deploy the KeyManager implementation
KeyManager implementation = new KeyManager();
console.log("KeyManager implementation deployed at:", address(implementation));

// Prepare initialization data
bytes memory initData = abi.encodeWithSelector(
KeyManager.initialize.selector,
manager
);

// Deploy the proxy and initialize it
ERC1967Proxy proxy = new ERC1967Proxy(
address(implementation),
initData
);
console.log("ERC1967Proxy deployed at:", address(proxy));

// Verify initialization
KeyManager proxyContract = KeyManager(address(proxy));
require(proxyContract.manager() == manager, "Manager not set correctly");

console.log("Deployment successful!");
console.log("Implementation:", address(implementation));
console.log("Proxy:", address(proxy));
console.log("Manager:", manager);

vm.stopBroadcast();

return (address(proxy), address(implementation));
}
}
76 changes: 76 additions & 0 deletions contracts/script/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Deploy KeyManager Contract

This script deploys the KeyManager contract to any Ethereum network.

## Quick Start

1. **Set up your environment:**
```bash
cp env.example .env
# Edit .env with your values
```

2. **Start a local blockchain (if testing locally):**
```bash
anvil
```

3. **Deploy:**
```bash
./script/deploy.sh
```

That's it! The script will deploy your contract and show you the addresses.

## What You Need

- **Manager Address**: Who will manage the contract (usually a multisig wallet)
- **RPC URL**: Where to deploy (localhost for testing, or a real network)
- **Mnemonic**: Your wallet phrase (optional for local testing)

## How It Works

The script deploys two contracts:
1. **KeyManager** - The actual contract with your business logic
2. **Proxy** - Points to the KeyManager, so you can upgrade it later

The proxy gets initialized with your manager address, and that's it!

## Configuration

All settings go in your `.env` file:

```bash
# Required: Who manages the contract
MANAGER_ADDRESS=0x1234567890123456789012345678901234567890

# Optional: Where to deploy (defaults to localhost)
RPC_URL=http://localhost:8545

# Optional: Your wallet phrase (defaults to Anvil's test account)
MNEMONIC="your twelve word mnemonic phrase here"
ACCOUNT_INDEX=0
```

## How it works
The deployment script:
1. **Deploys** the KeyManager implementation contract
2. **Creates** an ERC1967 proxy pointing to the implementation
3. **Initializes** the proxy with your manager address
4. **Verifies** the deployment was successful
5. **Returns** both proxy and implementation addresses


## Troubleshooting

**"Manager address not set"**
- Make sure you have `MANAGER_ADDRESS=0x...` in your `.env` file

**"Deployment failed"**
- Check your RPC URL works
- Make sure your wallet has enough ETH for gas
- Verify your mnemonic is correct

**Need help?**
- Make sure Foundry is installed: `forge --version`
- Check your `.env` file has all required values
Loading