Skip to content

Commit

Permalink
made the plonk verifier library external to the light client contract…
Browse files Browse the repository at this point in the history
… and removed oppenzeppelin related secrets to the another secret env file which you can replicate via the example file
  • Loading branch information
alysiahuggins committed Jul 25, 2024
1 parent 0863039 commit 0e7ab30
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 36 deletions.
20 changes: 1 addition & 19 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -122,22 +122,4 @@ ESPRESSO_BENCH_END_BLOCK=150
ESPRESSO_SEQUENCER_FETCH_RATE_LIMIT=25

# Query service stress test
ESPRESSO_NASTY_CLIENT_PORT=24011

# Openzeppelin Defender Deployment Profile
DEFENDER_KEY=
DEFENDER_SECRET=
FEE_CONTRACT_SALT=17
LIGHT_CLIENT_SALT=12
FEE_CONTRACT_UPGRADE_NAME="FeeContract.sol"
LIGHT_CLIENT_UPGRADE_NAME="LightClientV2.sol"
FOUNDRY_OUT=contracts/out

# The Ethereum address of the safe multisig wallet used to deploy and operate the contracts.
SAFE_MULTISIG_ADDRESS=
# The Ethereum private key of the wallet used for the proposing multisig transactions.
SAFE_ORCHESTRATOR_PRIVATE_KEY=

# Light Client
LIGHT_CLIENT_PROXY_CONTRACT_ADDRESS=
APPROVED_PROVER_ADDRESS=
ESPRESSO_NASTY_CLIENT_PORT=24011
20 changes: 20 additions & 0 deletions .env.contracts.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Openzeppelin Defender Deployment Profile
export DEFENDER_KEY=
export DEFENDER_SECRET=
export FEE_CONTRACT_SALT=
export LIGHT_CLIENT_SALT=
export FEE_CONTRACT_UPGRADE_NAME= #e.g "FeeContract.sol"
export LIGHT_CLIENT_UPGRADE_NAME=
export FOUNDRY_OUT=contracts/out

# The Ethereum address of the safe multisig wallet used to deploy and operate the contracts.
export SAFE_MULTISIG_ADDRESS=
# The Ethereum private key of the wallet used for the proposing multisig transactions.
export SAFE_ORCHESTRATOR_PRIVATE_KEY=

# Light Client
export LIGHT_CLIENT_PROXY_CONTRACT_ADDRESS=
export APPROVED_PROVER_ADDRESS=

# Plonk Verification Library Deployment with Defender
export PLONK_VERIFIER_SALT=
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@ wake-coverage.cov
# generated by failing serialization tests
data/*-actual.json
data/*-actual.bin

# Secret environment variables
.env.contracts
2 changes: 1 addition & 1 deletion contracts/script/FeeContractWithDefender.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ contract FeeContractDefenderDeployScript is Script {
Upgrades.deployUUPSProxy(contractName, abi.encodeCall(FC.initialize, (multisig)), opts);

//generate the deployment file path, output and write to the file
(string memory filePath, string memory fileData) = utils.generateDeploymentOutput(
(string memory filePath, string memory fileData) = utils.generateProxyDeploymentOutput(
contractName, contractSalt, proxyAddress, multisig, approvalProcessId, viaType
);
utils.writeJson(filePath, fileData);
Expand Down
2 changes: 1 addition & 1 deletion contracts/script/LightClientWithDefender.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ contract LightClientDefenderDeployScript is Script {
);

//generate the file path, file output and write to the file
(string memory filePath, string memory fileData) = utils.generateDeploymentOutput(
(string memory filePath, string memory fileData) = utils.generateProxyDeploymentOutput(
contractName,
contractSalt,
proxy,
Expand Down
54 changes: 54 additions & 0 deletions contracts/script/PlonkVerifierWithDefender.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
pragma solidity ^0.8.20;

import { Script } from "forge-std/Script.sol";

import { Defender, ApprovalProcessResponse } from "openzeppelin-foundry-upgrades/Defender.sol";
import { Upgrades, Options } from "openzeppelin-foundry-upgrades/Upgrades.sol";
import { PlonkVerifier as PV } from "../src/libraries/PlonkVerifier.sol";
import { UtilsScript } from "./Utils.s.sol";

contract PlonkVerifierDefenderDeployScript is Script {
string public contractName = "PlonkVerifier.sol";
UtilsScript public utils = new UtilsScript();
uint256 public contractSalt = uint256(vm.envInt("PLONK_VERIFIER_SALT"));

function run() public returns (address contractAddress, address multisig) {
ApprovalProcessResponse memory upgradeApprovalProcess = Defender.getDeployApprovalProcess();
multisig = upgradeApprovalProcess.via;

if (upgradeApprovalProcess.via == address(0)) {
revert(
string.concat(
"Deploy approval process with id ",
upgradeApprovalProcess.approvalProcessId,
" has no assigned address"
)
);
}

Options memory opts;
opts.defender.useDefenderDeploy = true;
opts.defender.skipLicenseType = true;
opts.defender.salt = bytes32(abi.encodePacked(contractSalt));

contractAddress = Defender.deployContract(contractName, opts.defender);

//generate the file path, file output and write to the file
(string memory filePath, string memory fileData) = utils.generateDeploymentOutput(
contractName,
contractSalt,
contractAddress,
multisig,
upgradeApprovalProcess.approvalProcessId,
upgradeApprovalProcess.viaType
);
utils.writeJson(filePath, fileData);

//generate the salt history file path, output and write to the file
(string memory saltFilePath, string memory saltFileData) =
utils.generateSaltOutput(contractName, contractSalt);
utils.writeJson(saltFilePath, saltFileData);

return (contractAddress, multisig);
}
}
117 changes: 105 additions & 12 deletions contracts/script/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ settings.
1. Choose a network
1. Select the approval process created in Step 2
1. Be sure to save DEFENDER_SECRET ("Team Secret key") and DEFENDER_KEY ("Team API Key"), that is shown at the end of
this step, into the .env file. The keys won't be available later at a later point.
this step, into the .env.contracts file. The keys won't be available later at a later point.

## Deployments

Expand All @@ -41,7 +41,12 @@ Steps:
1. Run the Deployment command.

```bash
forge clean && forge script contracts/script/FeeContractWithDefender.s.sol:FeeContractDefenderDeployScript --ffi --rpc-url https://ethereum-sepolia.publicnode.com --build-info true
source .env.contracts && \
forge clean && \
FeeContractWithDefender.s.sol:FeeContractDefenderDeployScript \
--ffi \
--rpc-url https://ethereum-sepolia.publicnode.com \
--build-info true
```

1. Go to the [deploy](https://defender.openzeppelin.com/v2/#/deploy) tab OpenZeppelin Defender's UI and click on the
Expand Down Expand Up @@ -85,16 +90,24 @@ multisig: address 0xc56fA6505d10bF322e01327e22479DE78C3Bf1cE
### Deploying the Light Client Contract
Read Deploying the Fee Contract for a more detailed version of this.
Read Deploying the Fee Contract for a more detailed version of this. Since the LightClient contract uses the
PlonkVerifier library, the PlonkVerifier library has to be deployed and then referenced at deployment time. Thus ensure
you've deployed the PlonkVerifier ([see steps below](#deploy-the-plonk-verifier-library-with-defender)) and set the
`$PLONK_VERIFIER_ADDRESS` variable in the command below. Each time modifications are made to the Plonk Verifier,
contracts that depend on it such as the Light Client contract have to be upgraded and should use the new PlonkVerifier
contract address as part of the deployment.

1. Initiate the Deployment with OpenZeppelin Defender

```bash
forge clean && forge script contracts/script/LightClientWithDefender.s.sol:LightClientDefenderDeployScript --ffi --rpc-url https://ethereum-sepolia.publicnode.com --build-info true
source .env.contracts && \
forge clean && \
forge script contracts/script/LightClientWithDefender.s.sol:LightClientDefenderDeployScript \
--ffi --rpc-url https://ethereum-sepolia.publicnode.com \
--build-info true \
--libraries contracts/src/libraries/PlonkVerifier.sol:PlonkVerifier:$PLONK_VERIFIER_ADDRESS
```

Follow the same steps as for the deployment of the fee contract above.
2. Verify the Contract

```bash
Expand All @@ -115,14 +128,18 @@ contracts/src/LightClient.sol:LightClient --watch
Steps:
1. Ensure that the salt has been updated in the `.env` file. The upgrade script retrieves the proxyAddress from the
previous deployment by reading a file in the following path:
1. Ensure that the salt has been updated in the `.env.contracts` file. The upgrade script retrieves the proxyAddress
from the previous deployment by reading a file in the following path:
`script/output/defenderDeployments/$CONTRACT_NAME/$CHAIN_ID/$SALT.json`. It knows the salt from a previous
deployment by reading the `saltHistory.json` file. Run the following command:
```bash
source .env.contracts && \
forge clean && \
forge script contracts/script/FeeContractWithDefender.s.sol:FeeContractDefenderUpgradeScript --ffi --rpc-url https://ethereum-sepolia.publicnode.com --build-info true
forge script contracts/script/FeeContractWithDefender.s.sol:FeeContractDefenderUpgradeScript \
--ffi \
--rpc-url https://ethereum-sepolia.publicnode.com \
--build-info true
```
2. This command requires you to go to OpenZeppelin Defender's UI to see the transaction. Click that transaction which
Expand All @@ -135,16 +152,27 @@ The transactions being confirmed are: (i) the deployment of the new fee contract

Ensure that you update the version in the `getVersion()` method of the latest implementation contract.
Since the LightClient contract uses the PlonkVerifier library, the PlonkVerifier library has to be deployed and then
referenced at deployment time. Thus ensure you've deployed the PlonkVerifier
([see steps below](#deploy-the-plonk-verifier-library-with-defender)) and set the `$PLONK_VERIFIER_ADDRESS` variable in
the command below. Each time modifications are made to the Plonk Verifier, contracts that depend on it such as the Light
Client contract have to be upgraded and should use the new PlonkVerifier contract address as part of the deployment.
Steps:
1. Ensure that the salt has been updated in the `.env` file. The upgrade script retrieves the proxyAddress from the
previous deployment by reading a file in the following path:
1. Ensure that the salt has been updated in the `.env.contracts` file. The upgrade script retrieves the proxyAddress
from the previous deployment by reading a file in the following path:
`script/output/defenderDeployments/$CONTRACT_NAME/$CHAIN_ID/$SALT.json`. It knows the salt from a previous
deployment by reading the `saltHistory.json` file. Run the following command:
```bash
source .env.contracts && \
forge clean && \
forge script contracts/script/LightClientWithDefender.s.sol:LightClientDefenderUpgradeScript --ffi --rpc-url https://ethereum-sepolia.publicnode.com --build-info true
forge script contracts/script/LightClientWithDefender.s.sol:LightClientDefenderUpgradeScript \
--ffi \
--rpc-url https://ethereum-sepolia.publicnode.com \
--build-info true \
--libraries contracts/src/libraries/PlonkVerifier.sol:PlonkVerifier:$PLONK_VERIFIER_ADDRESS
```
2. This command requires you to go to OpenZeppelin Defender's UI to see the transaction. Click that transaction which
Expand All @@ -169,3 +197,68 @@ This error occurs when build_info is set to true in the foundry.toml configurati
foundry profile is set to default when running commands like `just gen-bindings`.
Solution: `export FOUNDRY_PROFILE=default`
# Deploying Upgradable Contracts without OpenZeppelin Defender or a Safe Multisig Wallet
## LightClient Contract Deployment
```bash
forge script contracts/script/LightClient.s.sol:DeployLightClientContractScript $numBlocksPerEpoch $numInitValidators \
--sig 'run(uint32, uint32)' \
--ffi \
--rpc-url https://ethereum-sepolia.publicnode.com
```
## LightClient Contract Upgrade
```bash
forge script contracts/script/UpgradeLightClient.s.sol:UpgradeLightClientScript $admin $mostRecentlyDeployedProxy \
--sig 'run(address, address)' \
--ffi \
--rpc-url https://ethereum-sepolia.publicnode.com
```
# Deploy and Upgrade without Defender
Change the $MNEMONIC in the .env file to the one of the admin
To Deploy
```bash
forge script contracts/script/LightClient.s.sol:DeployLightClientContractScript $numBlocksPerEpoch $numInitValidators \
--sig 'run(uint32, uint32)' \
--ffi \
--rpc-url https://ethereum-sepolia.publicnode.com\
--broadcast --legacy
```
To Upgrade (assuming it's the same LightClient.sol file being used (pre-mainnet))

```bash
forge script contracts/script/UpgradeSameLightClient.s.sol:UpgradeLightClientScript $mnemonicOffset $mostRecentlyDeployedProxy \
--sig 'run(uint32, address)' \
--ffi \
--rpc-url https://ethereum-sepolia.publicnode.com \
--broadcast --legacy
```

Note: the `$mnemonicOffset` should be zero by default if address referenced by the `$MNEMONIC` in the `.env` is the
first address in that wallet. Otherwise, please specify the correct `$mnemonicOffset`

# Deploy the Plonk Verifier Library with Defender

The Plonk Verifier contract is not upgradeable and deploying we deploy with defender as part of our workflow so that we
can also deploy it with a multisig wallet. Each time modifications are made to the Plonk Verifier, contracts that depend
on it such as the Light Client contract have to be upgraded and should use the new PlonkVerifier contract address as
part of the deployment.

Ensure that you update the salt, `PLONK_VERIFIER_SALT`, in the `.env.contracts` file before each deployment.

```bash
source .env.contracts && \
forge clean && \
forge script contracts/script/PlonkVerifierWithDefender.s.sol:PlonkVerifierDefenderDeployScript \
--ffi \
--rpc-url https://ethereum-sepolia.publicnode.com \
--build-info true
```
32 changes: 31 additions & 1 deletion contracts/script/Utils.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ contract UtilsScript is Script {
return Strings.toHexString(uint256(uint160(address(addr))));
}

function generateDeploymentOutput(
function generateProxyDeploymentOutput(
string memory contractName,
uint256 contractSalt,
address proxy,
Expand Down Expand Up @@ -62,6 +62,36 @@ contract UtilsScript is Script {
return (filePath, obj3);
}

function generateDeploymentOutput(
string memory contractName,
uint256 contractSalt,
address contractAddress,
address multisig,
string memory approvalProcessId,
string memory viaType
) external returns (string memory filePath, string memory data) {
string memory outputDir = string.concat(
vm.projectRoot(),
"/contracts/script/output/defenderDeployments/",
contractName,
"/",
vm.toString(block.chainid),
"/"
);
filePath = string.concat(outputDir, Strings.toString(contractSalt), ".json");

createDir(outputDir);

string memory obj1 = "object";
vm.serializeAddress(obj1, "contractAddress", contractAddress);
vm.serializeAddress(obj1, "multisig", multisig);
vm.serializeString(obj1, "approvalProcessId", approvalProcessId);
vm.serializeString(obj1, "approvalType", viaType);
string memory obj3 = vm.serializeUint(obj1, "salt", contractSalt);

return (filePath, obj3);
}

function generateUpgradeOutput(
string memory originalContractName,
uint256 contractSalt,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"approvalProcessId": "a0dd5bf1-9766-4a2f-94b1-2a7ceb0dc5be",
"approvalType": "Gnosis Safe",
"multisig": "0xc56fA6505d10bF322e01327e22479DE78C3Bf1cE",
"proxyAddress": "0xfBCb14b42e6dDC81Dd4e02Dc1E35A9581A1F2200",
"salt": 14
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"contractName": "LightClient.sol",
"previousSalt": 12
"previousSalt": 14
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"approvalProcessId": "a0dd5bf1-9766-4a2f-94b1-2a7ceb0dc5be",
"approvalType": "Gnosis Safe",
"multisig": "0xc56fA6505d10bF322e01327e22479DE78C3Bf1cE",
"contractAddress": "0x7807612b7F4D8241E1128F0037d056DA2Eec0242",
"salt": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"contractName": "PlonkVerifier.sol",
"previousSalt": 2
}
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ verbosity = 1
[profile.quick]
fuzz = { runs = 10 }
invariant = { runs = 10 }
verbosity = 1
verbosity = 1

0 comments on commit 0e7ab30

Please sign in to comment.