Skip to content

Commit c0eeace

Browse files
committed
feat: deploy script for rollup contracts
1 parent 914146a commit c0eeace

File tree

5 files changed

+170
-10
lines changed

5 files changed

+170
-10
lines changed

.gitmodules

+9
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,12 @@
77
[submodule "lib/permit2"]
88
path = lib/permit2
99
url = https://github.com/Uniswap/permit2
10+
[submodule "lib/simple-erc20"]
11+
path = lib/simple-erc20
12+
url = https://github.com/init4tech/simple-erc20
13+
[submodule "lib/safe-smart-account"]
14+
path = lib/safe-smart-account
15+
url = https://github.com/safe-global/safe-smart-account
16+
[submodule "lib/stablecoin-evm"]
17+
path = lib/stablecoin-evm
18+
url = https://github.com/circlefin/stablecoin-evm

script/DeployGnosisSafe.s.sol

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
pragma solidity 0.8.26;
3+
4+
// deps
5+
import {SafeL2} from "safe-smart-account/contracts/SafeL2.sol";
6+
import {SafeProxyFactory} from "safe-smart-account/contracts/proxies/SafeProxyFactory.sol";
7+
import {CompatibilityFallbackHandler} from "safe-smart-account/contracts/handler/CompatibilityFallbackHandler.sol";
8+
// script deps
9+
import {Script, console2} from "forge-std/Script.sol";
10+
11+
struct SafeSetup {
12+
address[] owners;
13+
uint256 threshold;
14+
address to;
15+
bytes data;
16+
address fallbackHandler;
17+
address paymentToken;
18+
uint256 payment;
19+
address payable paymentReceiver;
20+
uint256 saltNonce;
21+
}
22+
23+
function deployGnosisCore() returns (address factory, address singleton, address fallbackHandler) {
24+
factory = address(new SafeProxyFactory{salt: "zenith.gnosisFactory"}());
25+
singleton = address(new SafeL2{salt: "zenith.gnosisSingleton"}());
26+
fallbackHandler = address(new CompatibilityFallbackHandler{salt: "zenith.gnosisFallbackHandlder"}());
27+
}
28+
29+
function deploySafeInstance(address factory, address singleton, SafeSetup memory setup) returns (address safe) {
30+
bytes memory init = abi.encodeWithSignature(
31+
"setup(address[],uint256,address,bytes,address,address,uint256,address)",
32+
setup.owners,
33+
setup.threshold,
34+
setup.to,
35+
setup.data,
36+
setup.fallbackHandler,
37+
setup.paymentToken,
38+
setup.payment,
39+
setup.paymentReceiver
40+
);
41+
safe = address(SafeProxyFactory(factory).createProxyWithNonce(singleton, init, setup.saltNonce));
42+
}
43+
44+
contract GnosisScript is Script {
45+
bytes32 constant SENTINEL_VALUE = 0x0000000000000000000000000000000000000000000000000000000000000001;
46+
47+
// example run:
48+
// forge script GnosisScript --sig "printOwnerSlots" "[0x1111111111111111111111111111111111111111, 0x2222222222222222222222222222222222222222]"
49+
function printOwnerSlots(address[] memory owners) public pure {
50+
for (uint256 i = 0; i <= owners.length; i++) {
51+
bytes32 value = (i == 0) ? SENTINEL_VALUE : addressToBytes32(owners[i - 1]);
52+
bytes32 slot = keccak256(abi.encodePacked(value, uint256(2)));
53+
console2.logBytes32(slot);
54+
}
55+
}
56+
57+
function addressToBytes32(address addr) internal pure returns (bytes32) {
58+
return bytes32(uint256(uint160(addr)));
59+
}
60+
}

script/DeployL2.s.sol

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
pragma solidity 0.8.26;
3+
4+
// system contracts
5+
import {RollupOrders} from "../src/orders/RollupOrders.sol";
6+
import {RollupPassage} from "../src/passage/RollupPassage.sol";
7+
// permit2
8+
import {deployPermit2} from "./DeployPermit2.s.sol";
9+
// gnosis safe
10+
import {deployGnosisCore, deploySafeInstance, SafeSetup} from "./DeployGnosisSafe.s.sol";
11+
// simple erc20
12+
import {SimpleERC20} from "simple-erc20/SimpleERC20.sol";
13+
// utils
14+
import {console2} from "forge-std/Script.sol";
15+
16+
address constant MINTER = 0x9999999999999999999999999999999999999999;
17+
address constant OWNER_ONE = 0x1111111111111111111111111111111111111111;
18+
address constant OWNER_TWO = 0x2222222222222222222222222222222222222222;
19+
20+
address constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
21+
22+
function deployPartOne() returns (address rollupPassage, address rollupOrders, address wbtc, address usdt) {
23+
// NOTE: must deploy Permit2 via https://github.com/Uniswap/permit2/blob/main/script/DeployPermit2.s.sol
24+
// in order to properly setup _CACHED_CHAIN_ID and _CACHED_DOMAIN_SEPARATOR
25+
26+
// deploy system contracts
27+
rollupPassage = address(new RollupPassage{salt: "zenith.rollupPassage"}(PERMIT2));
28+
console2.log("rollupPassage", rollupPassage);
29+
rollupOrders = address(new RollupOrders{salt: "zenith.rollupOrders"}(PERMIT2));
30+
console2.log("rollupOrders", rollupOrders);
31+
32+
// deploy simple erc20 tokens
33+
// make minter a recognizable addrs to aid in inspecting storage layout
34+
wbtc = address(new SimpleERC20{salt: "zenith.wbtc"}(MINTER, "Wrapped BTC", "WBTC"));
35+
usdt = address(new SimpleERC20{salt: "zenith.usdt"}(MINTER, "Tether USD", "USDT"));
36+
console2.log("wbtc", wbtc);
37+
console2.log("usdt", usdt);
38+
}
39+
40+
function deployPartTwo()
41+
returns (address gnosisFactory, address gnosisSingleton, address gnosisFallbackHandler, address usdcAdmin)
42+
{
43+
// deploy gnosis safe singleton & proxy factory
44+
(gnosisFactory, gnosisSingleton, gnosisFallbackHandler) = deployGnosisCore();
45+
console2.log("gnosisFactory", gnosisFactory);
46+
console2.log("gnosisSingleton", gnosisSingleton);
47+
console2.log("gnosisFallbackHandler", gnosisFallbackHandler);
48+
49+
// deploy a gnosis safe proxy as the USDC admin
50+
usdcAdmin = deploySafeInstance(gnosisFactory, gnosisSingleton, getUsdcAdminSetup(gnosisFallbackHandler));
51+
console2.log("usdcAdmin", usdcAdmin);
52+
53+
// NOTE: must deploy USDC via https://github.com/circlefin/stablecoin-evm/blob/master/scripts/deploy/deploy-fiat-token.s.sol
54+
// cannot import USDC deploy script because of git submodules -
55+
// it has a different remapping for openzeppelin contracts and can't compile in this repo
56+
}
57+
58+
// setup the gnosis safe with 2 owners, threshold of 1.
59+
// make the owners recognizable addrs to aid in inspecting storage layout
60+
function getUsdcAdminSetup(address fallbackHandler) pure returns (SafeSetup memory usdcAdminSetup) {
61+
address[] memory owners = new address[](2);
62+
owners[0] = OWNER_ONE;
63+
owners[1] = OWNER_TWO;
64+
usdcAdminSetup = SafeSetup({
65+
owners: owners,
66+
threshold: 1,
67+
to: address(0),
68+
data: "",
69+
fallbackHandler: fallbackHandler,
70+
paymentToken: address(0),
71+
payment: 0,
72+
paymentReceiver: payable(address(0)),
73+
saltNonce: 17001
74+
});
75+
}

script/Zenith.s.sol

-10
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ pragma solidity 0.8.26;
55
import {Zenith} from "../src/Zenith.sol";
66
import {Transactor} from "../src/Transactor.sol";
77
import {HostOrders} from "../src/orders/HostOrders.sol";
8-
import {RollupOrders} from "../src/orders/RollupOrders.sol";
98
import {Passage} from "../src/passage/Passage.sol";
10-
import {RollupPassage} from "../src/passage/RollupPassage.sol";
119
// utils
1210
import {Script} from "forge-std/Script.sol";
1311

@@ -28,14 +26,6 @@ contract ZenithScript is Script {
2826
m = new HostOrders(permit2);
2927
}
3028

31-
// deploy:
32-
// forge script ZenithScript --sig "deployL2(address)" --rpc-url $L2_RPC_URL --private-key $PRIVATE_KEY --broadcast $PERMIT_2
33-
function deployL2(address permit2) public returns (RollupPassage p, RollupOrders m) {
34-
vm.startBroadcast();
35-
p = new RollupPassage(permit2);
36-
m = new RollupOrders(permit2);
37-
}
38-
3929
// NOTE: script must be run using SequencerAdmin key
4030
// set sequencer:
4131
// forge script ZenithScript --sig "setSequencerRole(address,address)" --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast $ZENITH_ADDRESS $SEQUENCER_ADDRESS

script/ZenithL2.s.sol

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
pragma solidity 0.8.26;
3+
4+
// system contracts
5+
import {deployPartOne, deployPartTwo} from "./DeployL2.s.sol";
6+
// utils
7+
import {Script, console2} from "forge-std/Script.sol";
8+
9+
contract L2Script is Script {
10+
// deploy:
11+
// forge script L2Script --sig "deployOne()" --fork-url $ANVIL_URL --broadcast
12+
function deployOne() public returns (address rollupPassage, address rollupOrders, address wbtc, address usdt) {
13+
vm.startBroadcast();
14+
(rollupPassage, rollupOrders, wbtc, usdt) = deployPartOne();
15+
}
16+
17+
// deploy:
18+
// forge script L2Script --sig "deployTwo()" --fork-url $ANVIL_URL --broadcast
19+
function deployTwo()
20+
public
21+
returns (address gnosisFactory, address gnosisSingleton, address gnosisFallbackHandler, address usdcAdmin)
22+
{
23+
vm.startBroadcast();
24+
(gnosisFactory, gnosisSingleton, gnosisFallbackHandler, usdcAdmin) = deployPartTwo();
25+
}
26+
}

0 commit comments

Comments
 (0)