Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: deploy to Linea #18

Merged
merged 1 commit into from
Nov 1, 2024
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
[submodule "lib/foundry-devops"]
path = lib/foundry-devops
url = https://github.com/Cyfrin/foundry-devops
27 changes: 20 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,30 @@ $ forge test

## Owner privileges

The contract implementation aims to follow the [specification](https://github.com/waku-org/specs/blob/81b9fd588bff39894608746774b0903b067b5cdf/standards/core/rln-contract.md) that also describes ownership (see [Governance and upgradability](https://github.com/waku-org/specs/blob/81b9fd588bff39894608746774b0903b067b5cdf/standards/core/rln-contract.md#governance-and-upgradability) section).
The contract implementation aims to follow the
[specification](https://github.com/waku-org/specs/blob/81b9fd588bff39894608746774b0903b067b5cdf/standards/core/rln-contract.md)
that also describes ownership (see
[Governance and upgradability](https://github.com/waku-org/specs/blob/81b9fd588bff39894608746774b0903b067b5cdf/standards/core/rln-contract.md#governance-and-upgradability)
section).

As of commit afb858, the `Owner` privileges are assigned to the `msg.sender` of the membership registration transaction.
The `Owner` has the following privileges:

- set the token and price of one message published per epoch ([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/LinearPriceCalculator.sol#L25));
- authorize upgrades to a new implementation contract ([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L99));
- set the price calculator contract address ([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L267));
- set the maximum total rate limit of all memberships in the membership set ([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L273));
- set the minimum ([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L287)) and maximum ([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L280)) rate limit of one membership;
- set the duration of the active period ([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L295)) and grace period ([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L302)) of new memberships (see the [state transition diagram of a membership](https://github.com/waku-org/specs/blob/81b9fd588bff39894608746774b0903b067b5cdf/standards/core/rln-contract.md#membership-lifecycle)).
- set the token and price of one message published per epoch
([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/LinearPriceCalculator.sol#L25));
- authorize upgrades to a new implementation contract
([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L99));
- set the price calculator contract address
([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L267));
- set the maximum total rate limit of all memberships in the membership set
([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L273));
- set the minimum ([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L287)) and maximum
([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L280)) rate limit of one
membership;
- set the duration of the active period
([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L295)) and grace period
([link](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol#L302)) of new memberships (see the
[state transition diagram of a membership](https://github.com/waku-org/specs/blob/81b9fd588bff39894608746774b0903b067b5cdf/standards/core/rln-contract.md#membership-lifecycle)).

The pause functionality for contract functions is not yet implemented.

Expand Down
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
solc = "0.8.24"
src = "src"
test = "test"
fs_permissions = [{ access = "read", path = "./broadcast" }]

[fuzz]
max_test_rejects = 128_000
Expand Down
1 change: 1 addition & 0 deletions lib/foundry-devops
Submodule foundry-devops added at 47393d
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@
"adorno": "pnpm prettier:write && forge fmt && forge snapshot && pnpm gas-report",
"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": "export RPC_URL=https://rpc.cardona.zkevm-rpc.com && ./envCheck.sh && FOUNDRY_PROFILE=cardona forge script --chain 2442 script/Deploy.s.sol:Deploy --rpc-url $RPC_URL --broadcast --verify -vv --account $ACCOUNT --legacy --sender $ETH_FROM",
"deploy:linea_sepolia": "export RPC_URL=https://rpc.sepolia.linea.build && ./envCheck.sh && FOUNDRY_PROFILE=linea_sepolia forge script --chain 59141 script/Deploy.s.sol:Deploy --rpc-url $RPC_URL --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"
"deploy:localhost:price_calculator": "./envCheck.sh && forge script script/Deploy.s.sol:DeployPriceCalculator --rpc-url $RPC_URL --broadcast -vv --sender $ETH_FROM --account $ACCOUNT",
"deploy:localhost:wakurln_impl_v2": "./envCheck.sh && forge script script/Deploy.s.sol:DeployWakuRlnV2 --rpc-url $RPC_URL --broadcast -vv --sender $ETH_FROM --account $ACCOUNT",
"deploy:localhost:proxy": "./envCheck.sh && forge script script/Deploy.s.sol:DeployProxy --rpc-url $RPC_URL --broadcast -vv --sender $ETH_FROM --account $ACCOUNT",
"deploy:localhost": "npm run deploy:localhost:price_calculator && npm run deploy:localhost:wakurln_impl_v2 && npm run deploy:localhost:proxy",
"deploy:linea_sepolia:price_calculator": "export RPC_URL=https://rpc.sepolia.linea.build && ./envCheck.sh && FOUNDRY_PROFILE=linea_sepolia forge script --chain 59141 script/Deploy.s.sol:DeployPriceCalculator --rpc-url $RPC_URL --broadcast --verify -vv --account $ACCOUNT --legacy --sender $ETH_FROM",
"deploy:linea_sepolia:wakurln_impl_v2": "export RPC_URL=https://rpc.sepolia.linea.build && ./envCheck.sh && FOUNDRY_PROFILE=linea_sepolia forge script --chain 59141 script/Deploy.s.sol:DeployWakuRlnV2 --rpc-url $RPC_URL --broadcast --verify -vv --account $ACCOUNT --legacy --sender $ETH_FROM",
"deploy:linea_sepolia:proxy": "export RPC_URL=https://rpc.sepolia.linea.build && ./envCheck.sh && FOUNDRY_PROFILE=linea_sepolia forge script --chain 59141 script/Deploy.s.sol:DeployProxy --rpc-url $RPC_URL --broadcast --verify -vv --account $ACCOUNT --legacy --sender $ETH_FROM",
"deploy:linea_sepolia": "npm run deploy:linea_sepolia:price_calculator && npm run deploy:linea_sepolia:wakurln_impl_v2 && npm run deploy:linea_sepolia:proxy"
}
}
78 changes: 68 additions & 10 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@
pragma solidity >=0.8.19 <=0.9.0;

import { WakuRlnV2 } from "../src/WakuRlnV2.sol";
import { IPriceCalculator } from "../src/IPriceCalculator.sol";
import { LinearPriceCalculator } from "../src/LinearPriceCalculator.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 { DevOpsTools } from "lib/foundry-devops/src/DevOpsTools.sol";
import { BaseScript } from "./Base.s.sol";
import "forge-std/console.sol";

Check warning on line 12 in script/Deploy.s.sol

View workflow job for this annotation

GitHub Actions / lint

global import of path forge-std/console.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)

contract Deploy is BaseScript {
function run() public broadcast returns (WakuRlnV2 w, address impl) {
contract DeployPriceCalculator is BaseScript {
function run() public broadcast returns (address) {
address _token = _getTokenAddress();
return deploy(_token);
return address(deploy(_token));
}

function deploy(address _token) public returns (WakuRlnV2 w, address impl) {
address priceCalcAddr = address(new LinearPriceCalculator(_token, 0.05 ether));
impl = address(new WakuRlnV2());
bytes memory data = abi.encodeCall(WakuRlnV2.initialize, (priceCalcAddr, 160_000, 20, 600, 180 days, 30 days));
address proxy = address(new ERC1967Proxy(impl, data));
w = WakuRlnV2(proxy);
function deploy(address _token) public returns (IPriceCalculator) {
LinearPriceCalculator priceCalculator = new LinearPriceCalculator(_token, 0.05 ether);
return IPriceCalculator(priceCalculator);
}

function _getTokenAddress() internal view returns (address) {
Expand All @@ -36,15 +35,74 @@
}
}

contract DeployWakuRlnV2 is BaseScript {
function run() public broadcast returns (address) {
return address(deploy());
}

function deploy() public returns (WakuRlnV2) {
return new WakuRlnV2();
}
}

contract DeployProxy is BaseScript {
uint32 public constant MAX_TOTAL_RATELIMIT_PER_EPOCH = 160_000;
uint32 public constant MIN_RATELIMIT_PER_MEMBERSHIP = 20;
uint32 public constant MAX_RATELIMIT_PER_MEMBERSHIP = 600;
uint32 public constant ACTIVE_DURATION = 180 days;
uint32 public constant GRACE_PERIOD_DURATION = 30 days;

function run() public broadcast returns (address) {
address priceCalcAddr;
address wakuRlnV2ImplAddr;

try vm.envAddress("PRICE_CALCULATOR_ADDRESS") returns (address envPriceCalcAddress) {
console.log("Loading price calculator address from environment variable");
priceCalcAddr = envPriceCalcAddress;
} catch {
console.log("Loading price calculator address from broadcast directory");
priceCalcAddr = DevOpsTools.get_most_recent_deployment("LinearPriceCalculator", block.chainid);
}

try vm.envAddress("WAKURLNV2_ADDRESS") returns (address envWakuRlnV2ImplAddr) {
console.log("Loading WakuRlnV2 address from environment variable");
wakuRlnV2ImplAddr = envWakuRlnV2ImplAddr;
} catch {
console.log("Loading WakuRlnV2 address from broadcast directory");
wakuRlnV2ImplAddr = DevOpsTools.get_most_recent_deployment("WakuRlnV2", block.chainid);
}

console.log("Using price calculator address: %s", priceCalcAddr);
console.log("Using WakuRLNV2 address: %s", wakuRlnV2ImplAddr);

return address(deploy(priceCalcAddr, wakuRlnV2ImplAddr));
}

function deploy(address _priceCalcAddr, address _wakuRlnV2ImplAddr) public returns (ERC1967Proxy) {
bytes memory data = abi.encodeCall(
WakuRlnV2.initialize,
(
_priceCalcAddr,
MAX_TOTAL_RATELIMIT_PER_EPOCH,
MIN_RATELIMIT_PER_MEMBERSHIP,
MAX_RATELIMIT_PER_MEMBERSHIP,
ACTIVE_DURATION,
GRACE_PERIOD_DURATION
)
);
return new ERC1967Proxy(_wakuRlnV2ImplAddr, data);
}
}

contract DeployLibs is BaseScript {
function run() public broadcast returns (address poseidonT3, address lazyImt) {
bytes memory poseidonT3Bytecode = type(PoseidonT3).creationCode;
assembly {

Check warning on line 100 in script/Deploy.s.sol

View workflow job for this annotation

GitHub Actions / lint

Avoid to use inline assembly. It is acceptable only in rare cases
poseidonT3 := create(0, add(poseidonT3Bytecode, 0x20), mload(poseidonT3Bytecode))
}

bytes memory lazyImtBytecode = type(LazyIMT).creationCode;
assembly {

Check warning on line 105 in script/Deploy.s.sol

View workflow job for this annotation

GitHub Actions / lint

Avoid to use inline assembly. It is acceptable only in rare cases
lazyImt := create(0, add(lazyImtBytecode, 0x20), mload(lazyImtBytecode))
}
}
Expand Down
1 change: 0 additions & 1 deletion src/Membership.sol
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,9 @@
internal
onlyInitializing
{
require(0 < _minMembershipRateLimit);
require(_minMembershipRateLimit <= _maxMembershipRateLimit);

Check warning on line 153 in src/Membership.sol

View workflow job for this annotation

GitHub Actions / lint

Provide an error message for require
require(_maxMembershipRateLimit <= _maxTotalRateLimit);

Check warning on line 154 in src/Membership.sol

View workflow job for this annotation

GitHub Actions / lint

Provide an error message for require
require(_activeDurationForNewMemberships > 0);

Check warning on line 155 in src/Membership.sol

View workflow job for this annotation

GitHub Actions / lint

Provide an error message for require
// Note: grace period duration may be equal to zero

priceCalculator = IPriceCalculator(_priceCalculator);
Expand Down
20 changes: 11 additions & 9 deletions test/WakuRlnV2.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
pragma solidity >=0.8.19 <0.9.0;

import { Test } from "forge-std/Test.sol";
import { Deploy } from "../script/Deploy.s.sol";
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
import { DeployPriceCalculator, DeployWakuRlnV2, DeployProxy } from "../script/Deploy.s.sol";
import "../src/WakuRlnV2.sol"; // solhint-disable-line
import "../src/Membership.sol"; // solhint-disable-line
import { IPriceCalculator } from "../src/IPriceCalculator.sol";
Expand All @@ -16,19 +15,19 @@ import "forge-std/console.sol";

contract WakuRlnV2Test is Test {
WakuRlnV2 internal w;
address internal impl;
DeploymentConfig internal deploymentConfig;
TestToken internal token;

address internal deployer;

uint256[] noIdCommitmentsToErase = new uint256[](0);
uint256[] internal noIdCommitmentsToErase = new uint256[](0);

function setUp() public virtual {
token = new TestToken();
IPriceCalculator priceCalculator = (new DeployPriceCalculator()).deploy(address(token));
WakuRlnV2 wakuRlnV2 = (new DeployWakuRlnV2()).deploy();
ERC1967Proxy proxy = (new DeployProxy()).deploy(address(priceCalculator), address(wakuRlnV2));

Deploy deployment = new Deploy();
(w, impl) = deployment.deploy(address(token));
w = WakuRlnV2(address(proxy));

// Minting a large number of tokens to not have to worry about
// Not having enough balance
Expand Down Expand Up @@ -61,8 +60,11 @@ contract WakuRlnV2Test is Test {
w.root(),
13_801_897_483_540_040_307_162_267_952_866_411_686_127_372_014_953_358_983_481_592_640_000_001_877_295
);
(uint32 membershipRateLimit2, uint32 index2, uint256 rateCommitment2) = w.getMembershipInfo(idCommitment);
assertEq(membershipRateLimit2, membershipRateLimit);
uint32 fetchedMembershipRateLimit2;
uint32 index2;
uint256 rateCommitment2;
(fetchedMembershipRateLimit2, index2, rateCommitment2) = w.getMembershipInfo(idCommitment);
assertEq(fetchedMembershipRateLimit2, membershipRateLimit);
assertEq(index2, 0);
assertEq(rateCommitment2, rateCommitment);
uint256[20] memory proof = w.getMerkleProof(0);
Expand Down
Loading