Skip to content
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
5 changes: 5 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ jobs:
run: |
forge --version

- name: Run Forge fmt
run: |
forge fmt --check
id: fmt

- name: Run Forge build
run: |
forge build --sizes
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ docs/

# Dotenv file
.env

# OS files
.DS_Store
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.github/
foundry.toml
out/
lib/
cache/
cache/
9 changes: 6 additions & 3 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
{
"printWidth": 120,
"tabWidth": 4,
"useTabs": true,
"singleQuote": false,
"trailingComma": "all",
"overrides": [
{
"files": "*.sol",
"options": {
"useTabs": false,
"bracketSpacing": false
}
},
{
"files": ["*.json", "*.js", "*.ts"],
"options": {}
"files": "*.json",
"options": {
"useTabs": true,
"bracketSpacing": true
}
}
]
}
8 changes: 8 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ remappings = [
"createx/=lib/createx/src"
]

[fmt]
line_length = 120
tab_width = 4
quote_style = "double"
func_attrs_with_params_multiline = true
inline_attribute_style = "compact"
return_statement = "inline"

[fuzz]
runs = 5000
max_test_rejects = 1000000
Expand Down
195 changes: 97 additions & 98 deletions script/BaseScript.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,104 +2,103 @@
pragma solidity ^0.8.30;

import {Script, stdJson} from "forge-std/Script.sol";
import {ProxyForge} from "src/ProxyForge.sol";

abstract contract BaseScript is Script {
using stdJson for string;

string private constant DEFAULT_MNEMONIC = "test test test test test test test test test test test junk";

address internal broadcaster;

modifier broadcast() {
vm.startBroadcast(broadcaster);
_;
vm.stopBroadcast();
}

modifier fork(string memory chainAlias) {
vm.createSelectFork(chainAlias);
_;
}

function setUp() public virtual {
broadcaster = vm.rememberKey(configurePrivateKey());
}

function configurePrivateKey() internal view virtual returns (uint256 privateKey) {
privateKey = vm.envOr({
name: "PRIVATE_KEY",
defaultValue: vm.deriveKey({
mnemonic: vm.envOr({name: "MNEMONIC", defaultValue: DEFAULT_MNEMONIC}),
index: uint8(vm.envOr({name: "EOA_INDEX", defaultValue: uint256(0)}))
})
});
}

function generateJson(string memory path, string memory name, address instance, bytes32 salt) internal {
string memory json = "json";
json.serialize("address", instance);
json.serialize("blockNumber", vm.getBlockNumber());
json.serialize("name", name);
json.serialize("salt", salt);
json = json.serialize("timestamp", vm.getBlockTimestamp());
json.write(path);
}

function prompt(string memory promptText) internal returns (string memory input) {
return prompt(promptText, new string(0));
}

function prompt(string memory promptText, string memory defaultValue) internal returns (string memory input) {
input = vm.prompt(string.concat(promptText, " (default: `", defaultValue, "`)"));
if (bytes(input).length == 0) input = defaultValue;
}

function promptAddress(string memory promptText, address defaultValue) internal returns (address) {
return vm.parseAddress(prompt(promptText, vm.toString(defaultValue)));
}

function promptAddress(string memory promptText) internal returns (address) {
return promptAddress(promptText, address(0));
}

function promptBool(string memory promptText, bool defaultValue) internal returns (bool) {
return vm.parseBool(prompt(promptText, vm.toString(defaultValue)));
}

function promptBool(string memory promptText) internal returns (bool) {
return promptBool(promptText, false);
}

function promptUint256(string memory promptText, uint256 defaultValue) internal returns (uint256) {
return vm.parseUint(prompt(promptText, vm.toString(defaultValue)));
}

function promptUint256(string memory promptText) internal returns (uint256) {
return promptUint256(promptText, uint256(0));
}

function promptInt256(string memory promptText, int256 defaultValue) internal returns (int256) {
return vm.parseInt(prompt(promptText, vm.toString(defaultValue)));
}

function promptInt256(string memory promptText) internal returns (int256) {
return promptInt256(promptText, int256(0));
}

function promptBytes32(string memory promptText, bytes32 defaultValue) internal returns (bytes32) {
return vm.parseBytes32(prompt(promptText, vm.toString(defaultValue)));
}

function promptBytes32(string memory promptText) internal returns (bytes32) {
return promptBytes32(promptText, bytes32(0));
}

function promptBytes(string memory promptText, bytes memory defaultValue) internal returns (bytes memory) {
return vm.parseBytes(prompt(promptText, vm.toString(defaultValue)));
}

function promptBytes(string memory promptText) internal returns (bytes memory) {
return promptBytes(promptText, new bytes(0));
}
using stdJson for string;

string private constant DEFAULT_MNEMONIC = "test test test test test test test test test test test junk";

address internal broadcaster;

modifier broadcast() {
vm.startBroadcast(broadcaster);
_;
vm.stopBroadcast();
}

modifier fork(string memory chainAlias) {
vm.createSelectFork(chainAlias);
_;
}

function setUp() public virtual {
broadcaster = vm.rememberKey(configurePrivateKey());
}

function configurePrivateKey() internal view virtual returns (uint256 privateKey) {
privateKey = vm.envOr({
name: "PRIVATE_KEY",
defaultValue: vm.deriveKey({
mnemonic: vm.envOr({name: "MNEMONIC", defaultValue: DEFAULT_MNEMONIC}),
index: uint8(vm.envOr({name: "EOA_INDEX", defaultValue: uint256(0)}))
})
});
}

function generateJson(string memory path, string memory name, address instance, bytes32 salt) internal {
string memory json = "json";
json.serialize("address", instance);
json.serialize("blockNumber", vm.getBlockNumber());
json.serialize("name", name);
json.serialize("salt", salt);
json = json.serialize("timestamp", vm.getBlockTimestamp());
json.write(path);
}

function prompt(string memory promptText) internal returns (string memory input) {
return prompt(promptText, new string(0));
}

function prompt(string memory promptText, string memory defaultValue) internal returns (string memory input) {
input = vm.prompt(string.concat(promptText, " (default: `", defaultValue, "`)"));
if (bytes(input).length == 0) input = defaultValue;
}

function promptAddress(string memory promptText, address defaultValue) internal returns (address) {
return vm.parseAddress(prompt(promptText, vm.toString(defaultValue)));
}

function promptAddress(string memory promptText) internal returns (address) {
return promptAddress(promptText, address(0));
}

function promptBool(string memory promptText, bool defaultValue) internal returns (bool) {
return vm.parseBool(prompt(promptText, vm.toString(defaultValue)));
}

function promptBool(string memory promptText) internal returns (bool) {
return promptBool(promptText, false);
}

function promptUint256(string memory promptText, uint256 defaultValue) internal returns (uint256) {
return vm.parseUint(prompt(promptText, vm.toString(defaultValue)));
}

function promptUint256(string memory promptText) internal returns (uint256) {
return promptUint256(promptText, uint256(0));
}

function promptInt256(string memory promptText, int256 defaultValue) internal returns (int256) {
return vm.parseInt(prompt(promptText, vm.toString(defaultValue)));
}

function promptInt256(string memory promptText) internal returns (int256) {
return promptInt256(promptText, int256(0));
}

function promptBytes32(string memory promptText, bytes32 defaultValue) internal returns (bytes32) {
return vm.parseBytes32(prompt(promptText, vm.toString(defaultValue)));
}

function promptBytes32(string memory promptText) internal returns (bytes32) {
return promptBytes32(promptText, bytes32(0));
}

function promptBytes(string memory promptText, bytes memory defaultValue) internal returns (bytes memory) {
return vm.parseBytes(prompt(promptText, vm.toString(defaultValue)));
}

function promptBytes(string memory promptText) internal returns (bytes memory) {
return promptBytes(promptText, new bytes(0));
}
}
34 changes: 18 additions & 16 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,27 @@ import {ProxyForge} from "src/ProxyForge.sol";
import {BaseScript} from "./BaseScript.sol";

contract Deploy is BaseScript {
string internal constant DEFAULT_CHAINS = "ethereum, optimism, polygon, base, arbitrum";
string internal constant DEFAULT_CHAINS = "ethereum, optimism, polygon, base, arbitrum";

bytes32 internal constant DEFAULT_SALT = 0x0000000000000000000000000000000000000000000050726f7879466f726765;
bytes32 internal constant DEFAULT_SALT = 0x0000000000000000000000000000000000000000000050726f7879466f726765;

bytes32 internal salt;
bytes32 internal salt;

function setUp() public virtual override {
super.setUp();
salt = vm.envOr({name: "SALT", defaultValue: DEFAULT_SALT});
}
function setUp() public virtual override {
super.setUp();
salt = vm.envOr({name: "SALT", defaultValue: DEFAULT_SALT});
}

function run() external {
string memory input = prompt("Chains separated by ','", DEFAULT_CHAINS);
string[] memory chains = vm.split(vm.replace(input, " ", ""), ",");
for (uint256 i; i < chains.length; ++i) deployOnChain(chains[i]);
}
function run() external {
string memory input = prompt("Chains separated by ','", DEFAULT_CHAINS);
string[] memory chains = vm.split(vm.replace(input, " ", ""), ",");
for (uint256 i; i < chains.length; ++i) {
deployOnChain(chains[i]);
}
}

function deployOnChain(string memory chainAlias) internal fork(chainAlias) broadcast {
string memory path = string.concat("./deployments/", vm.toString(block.chainid), ".json");
generateJson(path, "ProxyForge", address(new ProxyForge{salt: salt}()), salt);
}
function deployOnChain(string memory chainAlias) internal fork(chainAlias) broadcast {
string memory path = string.concat("./deployments/", vm.toString(block.chainid), ".json");
generateJson(path, "ProxyForge", address(new ProxyForge{salt: salt}()), salt);
}
}
30 changes: 15 additions & 15 deletions script/DeployProxy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@ import {IProxyForge} from "src/interfaces/IProxyForge.sol";
import {BaseScript} from "./BaseScript.sol";

contract DeployProxy is BaseScript {
IProxyForge internal constant FORGE = IProxyForge(0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe);
IProxyForge internal constant FORGE = IProxyForge(0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe);

function run() external broadcast returns (address proxy) {
require(address(FORGE).code.length != 0, "ProxyForge not exists");
function run() external broadcast returns (address proxy) {
require(address(FORGE).code.length != 0, "ProxyForge not exists");

address implementation = vm.promptAddress("Implementation");
address owner = promptAddress("Owner", broadcaster);
address implementation = vm.promptAddress("Implementation");
address owner = promptAddress("Owner", broadcaster);

bool isDeterministic = promptBool("Is Deterministic");
bytes32 salt;
if (isDeterministic) salt = promptBytes32("Salt");
bool isDeterministic = promptBool("Is Deterministic");
bytes32 salt;
if (isDeterministic) salt = promptBytes32("Salt");

bytes memory data = promptBytes("Data");
uint256 value;
if (data.length != 0) value = promptUint256("msg.value");
bytes memory data = promptBytes("Data");
uint256 value;
if (data.length != 0) value = promptUint256("msg.value");

proxy = isDeterministic
? FORGE.deployDeterministicAndCall{value: value}(implementation, owner, salt, data)
: FORGE.deployAndCall{value: value}(implementation, owner, data);
}
proxy = isDeterministic
? FORGE.deployDeterministicAndCall{value: value}(implementation, owner, salt, data)
: FORGE.deployAndCall{value: value}(implementation, owner, data);
}
}
20 changes: 10 additions & 10 deletions script/UpgradeProxy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ import {IProxyForge} from "src/interfaces/IProxyForge.sol";
import {BaseScript} from "./BaseScript.sol";

contract UpgradeProxy is BaseScript {
IProxyForge internal constant FORGE = IProxyForge(0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe);
IProxyForge internal constant FORGE = IProxyForge(0x58b819827cB18Ba425906C69E1Bfb22F27Cb1bCe);

function run() external broadcast {
require(address(FORGE).code.length != 0, "ProxyForge not exists");
function run() external broadcast {
require(address(FORGE).code.length != 0, "ProxyForge not exists");

address proxy = vm.promptAddress("Proxy");
address implementation = vm.promptAddress("Implementation");
address proxy = vm.promptAddress("Proxy");
address implementation = vm.promptAddress("Implementation");

bytes memory data = promptBytes("Data");
uint256 value;
if (data.length != 0) value = promptUint256("msg.value");
bytes memory data = promptBytes("Data");
uint256 value;
if (data.length != 0) value = promptUint256("msg.value");

FORGE.upgradeAndCall{value: value}(proxy, implementation, data);
}
FORGE.upgradeAndCall{value: value}(proxy, implementation, data);
}
}
Loading