Skip to content

Commit 403a31c

Browse files
authored
Merge pull request #25 from movementlabsxyz/feat/pcp-migration
[protocol] pcp contracts
2 parents 72f08ae + da20abc commit 403a31c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+7281
-6
lines changed
Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# MCR - L1 contract
1+
# L1 contracts
22

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

@@ -8,9 +8,12 @@ forge test
88

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

11-
# Implementation
12-
## Description
11+
## Implementation
12+
13+
### Description
14+
1315
For a given block height, MCR selects the earliest block commitment that matches the supermajority of stake for a given epoch by:
16+
1417
1. Fixing the stake parameters for the epoch; all stake changes apply to the next epoch.
1518
2. Tracking commitments for each block height until one exceeds the supermajority of stake.
1619

@@ -20,14 +23,14 @@ For a given block height, MCR selects the earliest block commitment that matches
2023
2124
The stake is fixed for an epoch, so only commitments for a specific block height are considered, allowing for a straightforward proof.
2225

23-
**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).
26+
**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).
2427

2528
**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))$.
2629

27-
We require that
30+
We require that
2831

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

33-
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.
36+
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.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Compiler files
2+
cache/
3+
out/
4+
broadcast/
5+
6+
lib/
7+
8+
# Ignores development broadcast logs
9+
!/broadcast
10+
/broadcast/*/31337/
11+
/broadcast/**/dry-run/
12+
broadcast
13+
14+
# Docs
15+
docs/
16+
17+
# Dotenv file
18+
.env
19+
20+
.vscode/
21+
22+
node_modules/
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# L1 contracts
2+
3+
This directory contains the implementation of the PCP settlement smart contract. To test the contract, run:
4+
5+
## Installation
6+
7+
```bash
8+
chmod +x install-deps.sh
9+
./install-deps.sh
10+
```
11+
12+
## Testing
13+
14+
After installing the dependencies, run
15+
16+
```bash
17+
forge test
18+
```
19+
20+
There is a long-running test covering over 50 epochs. It will likely take a few seconds to run.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[profile.default]
2+
src = "src"
3+
out = "out"
4+
libs = ["lib"]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/bash
2+
3+
# Remove existing libs
4+
rm -rf lib/
5+
6+
# Install all dependencies
7+
forge install foundry-rs/forge-std --no-commit
8+
forge install OpenZeppelin/openzeppelin-contracts --no-commit
9+
forge install safe-global/safe-smart-account --no-commit
10+
forge install transmissions11/solmate --no-commit
11+
forge install OpenZeppelin/openzeppelin-contracts-upgradeable --no-commit
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
2+
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
3+
@createx/=lib/createx/src/
4+
ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/
5+
erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/
6+
forge-std/=lib/forge-std/src/
7+
murky/=lib/murky/
8+
openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/
9+
openzeppelin-contracts/=lib/openzeppelin-contracts/
10+
openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/
11+
openzeppelin/=lib/createx/lib/openzeppelin-contracts/contracts/
12+
@safe-smart-account/=lib/safe-smart-account/
13+
solady/=lib/createx/lib/solady/
14+
solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
pragma solidity ^0.8.13;
2+
3+
import "forge-std/Script.sol";
4+
import {MOVEToken} from "../src/token/MOVEToken.sol";
5+
import { Helper } from "./helpers/Helper.sol";
6+
import { PCPDeployer } from "./PCPDeployer.s.sol";
7+
import { MovementStakingDeployer } from "./MovementStakingDeployer.s.sol";
8+
import { StlMoveDeployer } from "./StlMoveDeployer.s.sol";
9+
import { MOVETokenDeployer } from "./MOVETokenDeployer.s.sol";
10+
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
11+
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
12+
13+
contract CoreDeployer is PCPDeployer, MovementStakingDeployer, StlMoveDeployer, MOVETokenDeployer {
14+
15+
function run() external override(PCPDeployer, MovementStakingDeployer, StlMoveDeployer, MOVETokenDeployer) {
16+
17+
// load config and deployments data
18+
_loadExternalData();
19+
20+
uint256 signer = vm.envUint("PRIVATE_KEY");
21+
vm.startBroadcast(signer);
22+
23+
// Deploy CREATE3Factory, Safes and Timelock if not deployed
24+
_deployDependencies();
25+
26+
// Deploy or upgrade contracts conditionally
27+
deployment.moveAdmin == ZERO && deployment.move == ZERO ?
28+
_deployMove() : deployment.moveAdmin != ZERO && deployment.move != ZERO ?
29+
// if move is already deployed, upgrade it
30+
_upgradeMove() : revert("MOVE: both admin and proxy should be registered");
31+
32+
// requires move to be deployed
33+
deployment.stakingAdmin == ZERO && deployment.staking == ZERO && deployment.move != ZERO ?
34+
_deployStaking() : deployment.stakingAdmin != ZERO && deployment.staking != ZERO ?
35+
// if staking is already deployed, upgrade it
36+
_upgradeStaking() : revert("STAKING: both admin and proxy should be registered");
37+
38+
// requires move to be deployed
39+
deployment.stlMoveAdmin == ZERO && deployment.stlMove == ZERO && deployment.move != ZERO ?
40+
_deployStlMove() : deployment.stlMoveAdmin != ZERO && deployment.stlMove != ZERO ?
41+
// if stlMove is already deployed, upgrade it
42+
_upgradeStlMove() : revert("STL: both admin and proxy should be registered");
43+
44+
// requires staking and move to be deployed
45+
deployment.pcpAdmin == ZERO && deployment.pcp == ZERO && deployment.move != ZERO && deployment.staking != ZERO ?
46+
_deployPCP() : deployment.pcpAdmin != ZERO && deployment.pcp != ZERO ?
47+
// if pcp is already deployed, upgrade it
48+
_upgradePCP() : revert("PCP: both admin and proxy should be registered");
49+
50+
// Only write to file if chainid is not running a foundry local chain and if broadcasting
51+
if (block.chainid == foundryChainId) {
52+
_allowSameContract();
53+
_upgradeMove();
54+
_upgradeStaking();
55+
_upgradeStlMove();
56+
_upgradePCP();
57+
} else {
58+
if (vm.isContext(VmSafe.ForgeContext.ScriptBroadcast)) {
59+
_writeDeployments();
60+
}
61+
}
62+
63+
vm.stopBroadcast();
64+
}
65+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
pragma solidity ^0.8.19;
2+
3+
import "forge-std/Script.sol";
4+
import "../src/token/MOVETokenDev.sol";
5+
import {IMintableToken, MintableToken} from "../src/token/base/MintableToken.sol";
6+
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
7+
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
8+
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
9+
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
10+
import {Helper} from "./helpers/Helper.sol";
11+
12+
contract DeployMOVETokenDev is Helper {
13+
address public manager = 0x5A368EDEbF574162B84f8ECFE48e9De4f520E087;
14+
uint256 public signer = vm.envUint("TEST_1");
15+
function run() external {
16+
vm.startBroadcast(signer);
17+
18+
MOVETokenDev moveTokenImplementation = new MOVETokenDev();
19+
TransparentUpgradeableProxy moveTokenProxy = new TransparentUpgradeableProxy(
20+
address(moveTokenImplementation),
21+
manager,
22+
abi.encodeWithSignature("initialize(address)", manager)
23+
);
24+
25+
console.log("Move Token Proxy: %s", address(moveTokenProxy));
26+
27+
vm.stopBroadcast();
28+
}
29+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.19;
3+
4+
import "forge-std/Script.sol";
5+
import "../src/settlement/PCP.sol";
6+
import {IMintableToken, MintableToken} from "../src/token/base/MintableToken.sol";
7+
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
8+
9+
contract DeployPCP is Script {
10+
function run() public {
11+
// Load Safe addresses from deployments.json
12+
string memory root = vm.projectRoot();
13+
string memory path = string.concat(root, "/script/helpers/safe-deployments.json");
14+
string memory json = vm.readFile(path);
15+
16+
address safe = abi.decode(vm.parseJson(json, ".Safe"), (address));
17+
address handler = abi.decode(vm.parseJson(json, ".FallbackHandler"), (address));
18+
address factory = abi.decode(vm.parseJson(json, ".SafeFactory"), (address));
19+
20+
vm.startBroadcast();
21+
22+
// Deploy PCP implementation and proxy
23+
PCP pcpImplementation = new PCP();
24+
25+
// Get MOVE token and staking addresses from deployments
26+
string memory deploymentsPath = string.concat(root, "/script/helpers/deployments.json");
27+
string memory deploymentsJson = vm.readFile(deploymentsPath);
28+
address moveToken = abi.decode(vm.parseJson(deploymentsJson, ".3151908.move"), (address));
29+
address staking = abi.decode(vm.parseJson(deploymentsJson, ".3151908.staking"), (address));
30+
31+
// Initialize PCP with production settings
32+
address[] memory custodians = new address[](1);
33+
custodians[0] = moveToken; // The MOVE token is the custodian for rewards
34+
35+
bytes memory pcpData = abi.encodeCall(
36+
PCP.initialize,
37+
(
38+
IMovementStaking(staking), // _stakingContract: address of staking contract
39+
0, // _lastPostconfirmedSuperBlockHeight: start from genesis
40+
5, // _leadingSuperBlockTolerance: max blocks ahead of last confirmed
41+
20 seconds, // _epochDuration: how long an epoch lasts
42+
custodians, // _custodians: array with moveToken address for rewards
43+
10 seconds, // _postconfirmerDuration: how long a postconfirmer serves
44+
moveToken // _moveTokenAddress: primary custodian for rewards in staking
45+
)
46+
);
47+
address pcpProxy = address(new ERC1967Proxy(address(pcpImplementation), pcpData));
48+
49+
// Save PCP address to deployments
50+
console.log("PCP implementation deployed to:", address(pcpImplementation));
51+
console.log("PCP proxy deployed to:", pcpProxy);
52+
53+
vm.stopBroadcast();
54+
}
55+
}

0 commit comments

Comments
 (0)