Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 9 additions & 6 deletions protocol/mcr/dlu/eth/contracts/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MCR - L1 contract
# L1 contracts

This directory contains the implementation of the MRC settlement smart contract. To test the contract, run:

Expand All @@ -8,9 +8,12 @@ forge test

There is a long-running test covering over 50 epochs. It will likely take a few seconds to run.

# Implementation
## Description
## Implementation

### Description

For a given block height, MCR selects the earliest block commitment that matches the supermajority of stake for a given epoch by:

1. Fixing the stake parameters for the epoch; all stake changes apply to the next epoch.
2. Tracking commitments for each block height until one exceeds the supermajority of stake.

Expand All @@ -20,14 +23,14 @@ For a given block height, MCR selects the earliest block commitment that matches

The stake is fixed for an epoch, so only commitments for a specific block height are considered, allowing for a straightforward proof.

**Commitment**. Let $v: C \to V$ map a commitment to its validator, where $C$ represent all possible commitments and $V$ is the set of validators. Since commitments are ordered by L1 in the L1-blocks, let $C'$ be an ordered subset of $C$ with $k$ elements (i.e. up to the $k$-th commitment).
**Commitment**. Let $v: C \to V$ map a commitment to its validator, where $C$ represent all possible commitments and $V$ is the set of validators. Since commitments are ordered by L1 in the L1-blocks, let $C'$ be an ordered subset of $C$ with $k$ elements (i.e. up to the $k$-th commitment).

**Stake**. Let $s: V \to \mathbb{N}$ map a validator to their stake and $S(C',i) = \sum_{j = 1}^{i} s(v(c_j))$ the cumulative stake up to the $i$-th commitment. $S$ is non-decreasing as $S(C',i) = S(C',i - 1) + s(v(c_i))$.

We require that
We require that

$$
S(C',i) > \frac{2}{3} TotalStake = \frac{2}{3} \times \sum_{u \in V} s(u),
$$

If $S(C', i)$ satisfies the condition, and $S(C',i-1)$ does not, then $c_i$ is returned by MCR. Due to the non-decreasing nature of $S$ with $i$, $c_i$ is the earliest commitment that can be returned.
If $S(C', i)$ satisfies the condition, and $S(C',i-1)$ does not, then $c_i$ is returned by MCR. Due to the non-decreasing nature of $S$ with $i$, $c_i$ is the earliest commitment that can be returned.
22 changes: 22 additions & 0 deletions protocol/pcp/dlu/eth/contracts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Compiler files
cache/
out/
broadcast/

lib/

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

# Docs
docs/

# Dotenv file
.env

.vscode/

node_modules/
20 changes: 20 additions & 0 deletions protocol/pcp/dlu/eth/contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# L1 contracts

This directory contains the implementation of the PCP settlement smart contract. To test the contract, run:

## Installation

```bash
chmod +x install-deps.sh
./install-deps.sh
```

## Testing

After installing the dependencies, run

```bash
forge test
```

There is a long-running test covering over 50 epochs. It will likely take a few seconds to run.
4 changes: 4 additions & 0 deletions protocol/pcp/dlu/eth/contracts/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
11 changes: 11 additions & 0 deletions protocol/pcp/dlu/eth/contracts/install-deps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

# Remove existing libs
rm -rf lib/

# Install all dependencies
forge install foundry-rs/forge-std --no-commit
forge install OpenZeppelin/openzeppelin-contracts --no-commit
forge install safe-global/safe-smart-account --no-commit
forge install transmissions11/solmate --no-commit
forge install OpenZeppelin/openzeppelin-contracts-upgradeable --no-commit
14 changes: 14 additions & 0 deletions protocol/pcp/dlu/eth/contracts/remappings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@createx/=lib/createx/src/
ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/
erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/
forge-std/=lib/forge-std/src/
murky/=lib/murky/
openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/
openzeppelin-contracts/=lib/openzeppelin-contracts/
openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/
openzeppelin/=lib/createx/lib/openzeppelin-contracts/contracts/
@safe-smart-account/=lib/safe-smart-account/
solady/=lib/createx/lib/solady/
solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/
65 changes: 65 additions & 0 deletions protocol/pcp/dlu/eth/contracts/script/CoreDeployer.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
pragma solidity ^0.8.13;

import "forge-std/Script.sol";
import {MOVEToken} from "../src/token/MOVEToken.sol";
import { Helper } from "./helpers/Helper.sol";
import { PCPDeployer } from "./PCPDeployer.s.sol";
import { MovementStakingDeployer } from "./MovementStakingDeployer.s.sol";
import { StlMoveDeployer } from "./StlMoveDeployer.s.sol";
import { MOVETokenDeployer } from "./MOVETokenDeployer.s.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";

contract CoreDeployer is PCPDeployer, MovementStakingDeployer, StlMoveDeployer, MOVETokenDeployer {

function run() external override(PCPDeployer, MovementStakingDeployer, StlMoveDeployer, MOVETokenDeployer) {

// load config and deployments data
_loadExternalData();

uint256 signer = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(signer);

// Deploy CREATE3Factory, Safes and Timelock if not deployed
_deployDependencies();

// Deploy or upgrade contracts conditionally
deployment.moveAdmin == ZERO && deployment.move == ZERO ?
_deployMove() : deployment.moveAdmin != ZERO && deployment.move != ZERO ?
// if move is already deployed, upgrade it
_upgradeMove() : revert("MOVE: both admin and proxy should be registered");

// requires move to be deployed
deployment.stakingAdmin == ZERO && deployment.staking == ZERO && deployment.move != ZERO ?
_deployStaking() : deployment.stakingAdmin != ZERO && deployment.staking != ZERO ?
// if staking is already deployed, upgrade it
_upgradeStaking() : revert("STAKING: both admin and proxy should be registered");

// requires move to be deployed
deployment.stlMoveAdmin == ZERO && deployment.stlMove == ZERO && deployment.move != ZERO ?
_deployStlMove() : deployment.stlMoveAdmin != ZERO && deployment.stlMove != ZERO ?
// if stlMove is already deployed, upgrade it
_upgradeStlMove() : revert("STL: both admin and proxy should be registered");

// requires staking and move to be deployed
deployment.pcpAdmin == ZERO && deployment.pcp == ZERO && deployment.move != ZERO && deployment.staking != ZERO ?
_deployPCP() : deployment.pcpAdmin != ZERO && deployment.pcp != ZERO ?
// if pcp is already deployed, upgrade it
_upgradePCP() : revert("PCP: both admin and proxy should be registered");

// Only write to file if chainid is not running a foundry local chain and if broadcasting
if (block.chainid == foundryChainId) {
_allowSameContract();
_upgradeMove();
_upgradeStaking();
_upgradeStlMove();
_upgradePCP();
} else {
if (vm.isContext(VmSafe.ForgeContext.ScriptBroadcast)) {
_writeDeployments();
}
}

vm.stopBroadcast();
}
}
29 changes: 29 additions & 0 deletions protocol/pcp/dlu/eth/contracts/script/DeployMOVETokenDev.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
pragma solidity ^0.8.19;

import "forge-std/Script.sol";
import "../src/token/MOVETokenDev.sol";
import {IMintableToken, MintableToken} from "../src/token/base/MintableToken.sol";
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {Helper} from "./helpers/Helper.sol";

contract DeployMOVETokenDev is Helper {
address public manager = 0x5A368EDEbF574162B84f8ECFE48e9De4f520E087;
uint256 public signer = vm.envUint("TEST_1");
function run() external {
vm.startBroadcast(signer);

MOVETokenDev moveTokenImplementation = new MOVETokenDev();
TransparentUpgradeableProxy moveTokenProxy = new TransparentUpgradeableProxy(
address(moveTokenImplementation),
manager,
abi.encodeWithSignature("initialize(address)", manager)
);

console.log("Move Token Proxy: %s", address(moveTokenProxy));

vm.stopBroadcast();
}
}
55 changes: 55 additions & 0 deletions protocol/pcp/dlu/eth/contracts/script/DeployPCP.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import "forge-std/Script.sol";
import "../src/settlement/PCP.sol";
import {IMintableToken, MintableToken} from "../src/token/base/MintableToken.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

contract DeployPCP is Script {
function run() public {
// Load Safe addresses from deployments.json
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/script/helpers/safe-deployments.json");
string memory json = vm.readFile(path);

address safe = abi.decode(vm.parseJson(json, ".Safe"), (address));
address handler = abi.decode(vm.parseJson(json, ".FallbackHandler"), (address));
address factory = abi.decode(vm.parseJson(json, ".SafeFactory"), (address));

vm.startBroadcast();

// Deploy PCP implementation and proxy
PCP pcpImplementation = new PCP();

// Get MOVE token and staking addresses from deployments
string memory deploymentsPath = string.concat(root, "/script/helpers/deployments.json");
string memory deploymentsJson = vm.readFile(deploymentsPath);
address moveToken = abi.decode(vm.parseJson(deploymentsJson, ".3151908.move"), (address));
address staking = abi.decode(vm.parseJson(deploymentsJson, ".3151908.staking"), (address));

// Initialize PCP with production settings
address[] memory custodians = new address[](1);
custodians[0] = moveToken; // The MOVE token is the custodian for rewards

bytes memory pcpData = abi.encodeCall(
PCP.initialize,
(
IMovementStaking(staking), // _stakingContract: address of staking contract
0, // _lastPostconfirmedSuperBlockHeight: start from genesis
5, // _leadingSuperBlockTolerance: max blocks ahead of last confirmed
20 seconds, // _epochDuration: how long an epoch lasts
custodians, // _custodians: array with moveToken address for rewards
10 seconds, // _postconfirmerDuration: how long a postconfirmer serves
moveToken // _moveTokenAddress: primary custodian for rewards in staking
)
);
address pcpProxy = address(new ERC1967Proxy(address(pcpImplementation), pcpData));

// Save PCP address to deployments
console.log("PCP implementation deployed to:", address(pcpImplementation));
console.log("PCP proxy deployed to:", pcpProxy);

vm.stopBroadcast();
}
}
Loading