chore: integrate proxy (#8)

* forge install: openzeppelin-foundry-upgrades

v0.3.1

* forge install: openzeppelin-contracts-upgradeable

v5.0.2

* test: integrate transparent proxy

* test: patch

* fix 

* fix: adorno

* fix: add cardona deployment

* fix: broken test for upgrade

* fix: cleanup

* fix: cleanup

* fix: lint

* fix: remove upgrade from Deploy.s.sol

* fix: envCheck
This commit is contained in:
Aaryamann Challani 2024-05-30 19:21:55 +05:30 committed by GitHub
parent 5f0d62d52e
commit 48542f3f04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 123 additions and 38 deletions

View File

@ -8,4 +8,5 @@ export API_KEY_OPTIMISTIC_ETHERSCAN="YOUR_API_KEY_OPTIMISTIC_ETHERSCAN"
export API_KEY_POLYGONSCAN="YOUR_API_KEY_POLYGONSCAN"
export API_KEY_SNOWTRACE="YOUR_API_KEY_SNOWTRACE"
export MNEMONIC="YOUR_MNEMONIC"
export ETH_FROM="YOUR_ETH_ADDRESS"
export FOUNDRY_PROFILE="default"

View File

@ -1,13 +1,14 @@
WakuRlnV2Test:test__IdCommitmentToMetadata__DoesntExist() (gas: 8299)
WakuRlnV2Test:test__InvalidPaginationQuery__EndIndexGTIdCommitmentIndex() (gas: 13351)
WakuRlnV2Test:test__InvalidPaginationQuery__StartIndexGTEndIndex() (gas: 11184)
WakuRlnV2Test:test__InvalidRegistration__DuplicateIdCommitment() (gas: 111313)
WakuRlnV2Test:test__InvalidRegistration__FullTree() (gas: 97043)
WakuRlnV2Test:test__InvalidRegistration__InvalidIdCommitment__LargerThanField() (gas: 9926)
WakuRlnV2Test:test__InvalidRegistration__InvalidIdCommitment__Zero() (gas: 9139)
WakuRlnV2Test:test__InvalidRegistration__InvalidUserMessageLimit__LargerThanMax() (gas: 10147)
WakuRlnV2Test:test__InvalidRegistration__InvalidUserMessageLimit__Zero() (gas: 9242)
WakuRlnV2Test:test__ValidPaginationQuery(uint32) (runs: 1002, μ: 402088, ~: 136269)
WakuRlnV2Test:test__ValidPaginationQuery__OneElement() (gas: 128461)
WakuRlnV2Test:test__ValidRegistration(uint256,uint32) (runs: 1001, μ: 133518, ~: 133518)
WakuRlnV2Test:test__ValidRegistration__kats() (gas: 108906)
WakuRlnV2Test:test__IdCommitmentToMetadata__DoesntExist() (gas: 16723)
WakuRlnV2Test:test__InvalidPaginationQuery__EndIndexGTIdCommitmentIndex() (gas: 18260)
WakuRlnV2Test:test__InvalidPaginationQuery__StartIndexGTEndIndex() (gas: 16083)
WakuRlnV2Test:test__InvalidRegistration__DuplicateIdCommitment() (gas: 99824)
WakuRlnV2Test:test__InvalidRegistration__FullTree() (gas: 14343)
WakuRlnV2Test:test__InvalidRegistration__InvalidIdCommitment__LargerThanField() (gas: 15258)
WakuRlnV2Test:test__InvalidRegistration__InvalidIdCommitment__Zero() (gas: 14046)
WakuRlnV2Test:test__InvalidRegistration__InvalidUserMessageLimit__LargerThanMax() (gas: 17639)
WakuRlnV2Test:test__InvalidRegistration__InvalidUserMessageLimit__Zero() (gas: 14126)
WakuRlnV2Test:test__Upgrade() (gas: 3668443)
WakuRlnV2Test:test__ValidPaginationQuery(uint32) (runs: 1000, μ: 446587, ~: 159861)
WakuRlnV2Test:test__ValidPaginationQuery__OneElement() (gas: 120064)
WakuRlnV2Test:test__ValidRegistration(uint256,uint32) (runs: 1000, μ: 124674, ~: 124674)
WakuRlnV2Test:test__ValidRegistration__kats() (gas: 96917)

6
.gitmodules vendored
View File

@ -2,3 +2,9 @@
branch = "v1"
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/openzeppelin-foundry-upgrades"]
path = lib/openzeppelin-foundry-upgrades
url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable

View File

@ -1,6 +1,10 @@
# This script is used to assert if require env vars are present for deployment
# RPC_URL: RPC URL for the network
# ACCOUNT: Accessed with `cast wallet` command
# ETH_FROM: Address to send transactions from
# we need ETH_FROM because of the following bug:
# https://github.com/foundry-rs/foundry/issues/7255
if [ -z "$RPC_URL" ]; then
echo "RPC_URL is required"
@ -11,3 +15,8 @@ if [ -z "$ACCOUNT" ]; then
echo "ACCOUNT is required"
exit 1
fi
if [ -z "$ETH_FROM" ]; then
echo "ETH_FROM is required"
exit 1
fi

View File

@ -5,7 +5,7 @@
block_timestamp = 1_680_220_800 # March 31, 2023 at 00:00 GMT
bytecode_hash = "none"
cbor_metadata = false
evm_version = "paris"
evm_version = "cancun"
fuzz = { runs = 1_000 }
gas_reports = ["*"]
libs = ["lib"]
@ -13,7 +13,7 @@
optimizer_runs = 10_000
out = "out"
script = "script"
solc = "0.8.19"
solc = "0.8.24"
src = "src"
test = "test"
@ -27,6 +27,7 @@ max_test_rejects = 128_000
[etherscan]
mainnet = { key = "${API_KEY_ETHERSCAN}" }
sepolia = { key = "${API_KEY_ETHERSCAN}" }
2442 = { key = "${API_KEY_CARDONA}", url = "https://api-cardona-zkevm.polygonscan.com/api" }
[fmt]
bracket_spacing = true
@ -41,3 +42,10 @@ max_test_rejects = 128_000
[rpc_endpoints]
localhost = "http://localhost:8545"
sepolia = "https://eth-sepolia.g.alchemy.com/v2/${API_KEY_ALCHEMY}"
2442 = "https://rpc.cardona.zkevm-rpc.com"
[profile.sepolia]
libraries = ["node_modules/@zk-kit/imt.sol/contracts/LazyIMT.sol:LazyIMT:0x22317F732AE9f9015b0866d03319a441FB42cd7f", "node_modules/poseidon-solidity/PoseidonT3.sol:PoseidonT3:0x4CF6285AC1E3ddAD6E1E378146CbCd3A6CA3Ed60"]
[profile.cardona]
libraries = ["node_modules/@zk-kit/imt.sol/contracts/LazyIMT.sol:LazyIMT:0x8176F5f2A49cDBcCB46487D9C839c45D0200A270", "node_modules/poseidon-solidity/PoseidonT3.sol:PoseidonT3:0x99419DF6428Bad6Fe117513129FACaD4864afdcF"]

2
lib/forge-std vendored

@ -1 +1 @@
Subproject commit 74cfb77e308dd188d2f58864aaf44963ae6b88b1
Subproject commit 978ac6fadb62f5f0b723c996f64be52eddba6801

@ -0,0 +1 @@
Subproject commit 0a71a5ebfbf4136cae3176e5cc9bcc5efc23f76b

1
lib/openzeppelin-foundry-upgrades vendored Submodule

@ -0,0 +1 @@
Subproject commit 4cd15fc50b141c77d8cc9ff8efb44d00e841a299

View File

@ -34,7 +34,8 @@
"gas-report": "forge test --gas-report 2>&1 | (tee /dev/tty | awk '/Test result:/ {found=1; buffer=\"\"; next} found && !/Ran/ {buffer=buffer $0 ORS} /Ran/ {found=0} END {printf \"%s\", buffer}' > .gas-report)",
"release": "commit-and-tag-version",
"adorno": "pnpm prettier:write && forge fmt && forge snapshot && pnpm gas-report",
"deploy:sepolia": "./envCheck.sh && forge script --chain sepolia script/Deploy.s.sol:Deploy --rpc-url $RPC_URL --broadcast --verify -vv --account $ACCOUNT --legacy",
"deploy:localhost": "./envCheck.sh && forge script script/Deploy.s.sol:Deploy --rpc-url $RPC_URL --broadcast -vv --account $ACCOUNT"
"deploy:sepolia": "./envCheck.sh && FOUNDRY_PROFILE=sepolia forge script --chain sepolia script/Deploy.s.sol:Deploy --rpc-url $RPC_URL --broadcast --verify -vv --account $ACCOUNT --legacy --sender $ETH_FROM",
"deploy:cardona": "./envCheck.sh && FOUNDRY_PROFILE=cardona forge script --chain 2442 script/Deploy.s.sol:Deploy --rpc-url https://rpc.cardona.zkevm-rpc.com --broadcast --verify -vv --account $ACCOUNT --legacy --sender $ETH_FROM",
"deploy:localhost": "./envCheck.sh && forge script script/Deploy.s.sol:Deploy --rpc-url $RPC_URL --broadcast -vv --account $ACCOUNT --sender $ETH_FROM"
}
}

View File

@ -1,3 +1,5 @@
forge-std/=lib/forge-std/src/
@zk-kit/imt.sol/=node_modules/@zk-kit/imt.sol/contracts
poseidon-solidity/=node_modules/poseidon-solidity/
@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/

View File

@ -2,11 +2,33 @@
pragma solidity >=0.8.19 <=0.9.0;
import { WakuRlnV2 } from "../src/WakuRlnV2.sol";
import { PoseidonT3 } from "poseidon-solidity/PoseidonT3.sol";
import { LazyIMT } from "@zk-kit/imt.sol/LazyIMT.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { BaseScript } from "./Base.s.sol";
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
contract Deploy is BaseScript {
function run() public broadcast returns (WakuRlnV2 w) {
w = new WakuRlnV2(20);
function run() public broadcast returns (WakuRlnV2 w, address impl) {
impl = address(new WakuRlnV2());
bytes memory data = abi.encodeCall(WakuRlnV2.initialize, (msg.sender, 20));
address proxy = address(new ERC1967Proxy(impl, data));
w = WakuRlnV2(proxy);
}
}
contract DeployLibs is BaseScript {
function run() public broadcast returns (address poseidonT3, address lazyImt) {
bytes memory poseidonT3Bytecode = type(PoseidonT3).creationCode;
assembly {
poseidonT3 := create(0, add(poseidonT3Bytecode, 0x20), mload(poseidonT3Bytecode))
}
bytes memory lazyImtBytecode = type(LazyIMT).creationCode;
assembly {
lazyImt := create(0, add(lazyImtBytecode, 0x20), mload(lazyImtBytecode))
}
}
}

View File

@ -1,10 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
pragma solidity 0.8.24;
import { LazyIMT, LazyIMTData } from "@zk-kit/imt.sol/LazyIMT.sol";
import { PoseidonT3 } from "poseidon-solidity/PoseidonT3.sol";
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
/// The tree is full
error FullTree();
@ -20,22 +23,22 @@ error InvalidUserMessageLimit(uint32 messageLimit);
/// Invalid pagination query
error InvalidPaginationQuery(uint256 startIndex, uint256 endIndex);
contract WakuRlnV2 {
contract WakuRlnV2 is Initializable, OwnableUpgradeable, UUPSUpgradeable {
/// @notice The Field
uint256 public constant Q =
21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617;
/// @notice The max message limit per epoch
uint32 public immutable MAX_MESSAGE_LIMIT;
uint32 public MAX_MESSAGE_LIMIT;
/// @notice The depth of the merkle tree
uint8 public constant DEPTH = 20;
/// @notice The size of the merkle tree, i.e 2^depth
uint32 public immutable SET_SIZE;
uint32 public SET_SIZE;
/// @notice The index of the next member to be registered
uint32 public idCommitmentIndex = 0;
uint32 public idCommitmentIndex;
/// @notice the membership metadata of the member
struct MembershipInfo {
@ -49,7 +52,7 @@ contract WakuRlnV2 {
mapping(uint256 => MembershipInfo) public memberInfo;
/// @notice the deployed block number
uint32 public immutable deployedBlockNumber;
uint32 public deployedBlockNumber;
/// @notice the stored imt data
LazyIMTData public imtData;
@ -74,14 +77,22 @@ contract WakuRlnV2 {
_;
}
/// @notice the constructor of the contract
constructor(uint32 maxMessageLimit) {
constructor() {
_disableInitializers();
}
function initialize(address initialOwner, uint32 maxMessageLimit) public initializer {
__Ownable_init(initialOwner);
__UUPSUpgradeable_init();
MAX_MESSAGE_LIMIT = maxMessageLimit;
SET_SIZE = uint32(1 << DEPTH);
deployedBlockNumber = uint32(block.number);
LazyIMT.init(imtData, DEPTH);
idCommitmentIndex = 0;
}
function _authorizeUpgrade(address newImplementation) internal override onlyOwner { } // solhint-disable-line
/// @notice Checks if a commitment is valid
/// @param idCommitment The idCommitment of the member
/// @return true if the commitment is valid, false otherwise

View File

@ -2,25 +2,22 @@
pragma solidity >=0.8.19 <0.9.0;
import { Test } from "forge-std/Test.sol";
import { stdStorage, StdStorage } from "forge-std/Test.sol";
import { Deploy } from "../script/Deploy.s.sol";
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
import "../src/WakuRlnV2.sol";
import "../src/WakuRlnV2.sol"; // solhint-disable-line
import { PoseidonT3 } from "poseidon-solidity/PoseidonT3.sol";
import { LazyIMT } from "@zk-kit/imt.sol/LazyIMT.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract WakuRlnV2Test is Test {
using stdStorage for StdStorage;
WakuRlnV2 internal w;
address internal impl;
DeploymentConfig internal deploymentConfig;
address internal deployer;
function setUp() public virtual {
Deploy deployment = new Deploy();
w = deployment.run();
(w, impl) = deployment.run();
}
function test__ValidRegistration__kats() external {
@ -90,7 +87,7 @@ contract WakuRlnV2Test is Test {
assertEq(fetchedRateCommitment, rateCommitment);
}
function test__IdCommitmentToMetadata__DoesntExist() external {
function test__IdCommitmentToMetadata__DoesntExist() external view {
uint256 idCommitment = 2;
(uint32 userMessageLimit, uint32 index, uint256 rateCommitment) = w.idCommitmentToMetadata(idCommitment);
assertEq(userMessageLimit, 0);
@ -137,7 +134,18 @@ contract WakuRlnV2Test is Test {
function test__InvalidRegistration__FullTree() external {
uint32 userMessageLimit = 2;
// we progress the tree to the last leaf
stdstore.target(address(w)).sig("idCommitmentIndex()").checked_write(1 << w.DEPTH());
/*| Name | Type | Slot | Offset | Bytes |
|---------------------|-----------------------------------------------------|------|--------|-------|
| MAX_MESSAGE_LIMIT | uint32 | 0 | 0 | 4 |
| SET_SIZE | uint32 | 0 | 4 | 4 |
| idCommitmentIndex | uint32 | 0 | 8 | 4 |
| memberInfo | mapping(uint256 => struct WakuRlnV2.MembershipInfo) | 1 | 0 | 32 |
| deployedBlockNumber | uint32 | 2 | 0 | 4 |
| imtData | struct LazyIMTData | 3 | 0 | 64 |*/
// we set MAX_MESSAGE_LIMIT to 20 (unaltered)
// we set SET_SIZE to 4294967295 (1 << 20) (unaltered)
// we set idCommitmentIndex to 4294967295 (1 << 20) (altered)
vm.store(address(w), bytes32(0), 0x0000000000000000000000000000000000000000ffffffffffffffff00000014);
vm.expectRevert(FullTree.selector);
w.register(1, userMessageLimit);
}
@ -179,4 +187,18 @@ contract WakuRlnV2Test is Test {
assertEq(commitments[i], rateCommitment);
}
}
function test__Upgrade() external {
address newImplementation = address(new WakuRlnV2());
bytes memory data;
UUPSUpgradeable(address(w)).upgradeToAndCall(newImplementation, data);
// ensure that the implementation is set correctly
// ref:
// solhint-disable-next-line
// https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades/blob/4cd15fc50b141c77d8cc9ff8efb44d00e841a299/src/internal/Core.sol#L289
address fetchedImpl = address(
uint160(uint256(vm.load(address(w), 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc)))
);
assertEq(fetchedImpl, newImplementation);
}
}