Skip to content
Open
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
8 changes: 4 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
forge build --sizes
id: build

- name: Run Forge tests
run: |
forge test -vvv
id: test
# - name: Run Forge tests
# run: |
# forge test -vvv
# id: test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ docs/

# Dotenv file
.env
.DS_Store
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
5 changes: 5 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ libs = ["lib"]
fs_permissions = [{ access = "read", path = "./"}]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options

remappings = [
"forge-std/=lib/forge-std/src/",
"@openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
]
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at e4f702
10 changes: 10 additions & 0 deletions roles-configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"admin": "0xDE2974737dcE6FCce14924C87506b6249E3Bf189",
"customExternalCallers": [
"0xC0896ab1A8cae8c2C1d27d011eb955Cca955580d",
"0xDE2974737dcE6FCce14924C87506b6249E3Bf189"
],
"pufferOpsMultisig": "0xC0896ab1A8cae8c2C1d27d011eb955Cca955580d",
"vault": "0x2ce0b4c55be864c9c5dfc71bcd522dec9378f368",
"withdrawalManager": "0xDE2974737dcE6FCce14924C87506b6249E3Bf189"
}
39 changes: 31 additions & 8 deletions script/CustomExternalCallNonRestakingValidators.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ interface IBeaconDepositContract {
) external payable;
}

// forge script script/CustomExternalCallNonRestakingValidators.s.sol:CustomExternalCallNonRestakingValidators --rpc-url=$HOLESKY_RPC_URL --account institutional-deployer-testnet -vvvv --sig "run(address,string)" 0x205A6BCF458a40E1a30a000166c793Ec54b0d9D5 example
// add --broadcast to broadcast the transaction
// forge script script/CustomExternalCallNonRestakingValidators.s.sol:CustomExternalCallNonRestakingValidators --rpc-url=$HOLESKY_RPC_URL --account institutional-deployer-testnet -vvvv --sig "run(string)" depositfilename
// This script assumes that the calldata will be executed on mainnet, so the beacon deposit contract address is hardcoded
contract CustomExternalCallNonRestakingValidators is Script {
using stdJson for string;

Expand All @@ -42,23 +42,36 @@ contract CustomExternalCallNonRestakingValidators is Script {
string withdrawal_credentials;
}

struct RolesConfiguration {
address admin;
address[] customExternalCallers;
address pufferOpsMultisig;
address vault;
address withdrawalManager;
}

bytes pubKey;
bytes withdrawalCredentials;
bytes signature;
bytes32 depositDataRoot;
uint256 amount;

function run(address payable institutionalVaultProxy, string calldata depositFileName) public {
vm.startBroadcast();
function run(string calldata depositFileName) public {
// vm.startBroadcast();

string memory root = vm.projectRoot();
string memory path = string.concat(root, "/validator_deposit_data/0x02/", depositFileName, ".json");
string memory rolesConfigurationPath = string.concat(root, "/roles-configuration.json");

console.log("Path:", path);
console.log("Roles configuration path:", rolesConfigurationPath);

string memory fileContent = vm.readFile(path);
bytes memory rawJson = vm.parseJson(fileContent);

RolesConfiguration memory accessManagerConfiguration =
abi.decode(vm.parseJson(vm.readFile(rolesConfigurationPath)), (RolesConfiguration));

ValidatorDepositData[] memory depositData = abi.decode(rawJson, (ValidatorDepositData[]));

for (uint256 i = 0; i < depositData.length; i++) {
Expand All @@ -71,12 +84,22 @@ contract CustomExternalCallNonRestakingValidators is Script {
IBeaconDepositContract.deposit, (pubKey, withdrawalCredentials, signature, depositDataRoot)
);

// TODO: Custom external call directly to the beacon deposit contract
IInstitutionalVault(institutionalVaultProxy).customExternalCall(
0x00000000219ab540356cBB839Cbe05303d7705Fa, data, amount
bytes memory customExternalCallData = abi.encodeCall(
IInstitutionalVault.customExternalCall,
// Hardcoded the beacon deposit contract address
(0x00000000219ab540356cBB839Cbe05303d7705Fa, data, amount)
);

console.log("Custom external call to the beacon deposit contract");
console.log("Vault:", accessManagerConfiguration.vault);
console.logBytes(customExternalCallData);

// TODO: Custom external call directly to the beacon deposit contract

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove all the commented code and TODO?

// IInstitutionalVault(institutionalVaultProxy).customExternalCall(
// accessManagerConfiguration.vault, data, amount
// );
}

vm.stopBroadcast();
// vm.stopBroadcast();
}
}
126 changes: 126 additions & 0 deletions script/InitialAccessManagerSetup.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import {Script} from "forge-std/Script.sol";
import {stdJson} from "forge-std/StdJson.sol";
import {console} from "forge-std/console.sol";
import {AccessManager} from "@openzeppelin-contracts/access/manager/AccessManager.sol";
import {Multicall} from "@openzeppelin-contracts/utils/Multicall.sol";
import {IInstitutionalVault} from "../src/interface/IInstitutionalVault.sol";

// forge script script/InitialAccessManagerSetup.s.sol:InitialAccessManagerSetup -vvvv
contract InitialAccessManagerSetup is Script {
using stdJson for string;

uint64 public constant ADMIN_ROLE_ID = type(uint64).min; // 0
uint64 public constant DEPOSITOR_ROLE_ID = 1;
uint64 public constant WITHDRAWER_ROLE_ID = 2;
uint64 public constant CUSTOM_EXTERNAL_CALLER_ROLE_ID = 3;
uint64 public constant WITHDRAWAL_MANAGER_ROLE_ID = 4;
uint64 public constant ORACLE_ROLE_ID = 5;
Comment on lines +15 to +20

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe move the roles to its own file to make it more manageable


struct RolesConfiguration {
address admin;
address[] customExternalCallers;
address pufferOpsMultisig;
address vault;
address withdrawalManager;
}

function run() public view {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/roles-configuration.json");

console.log("Path:", path);

string memory fileContent = vm.readFile(path);
bytes memory rawJson = vm.parseJson(fileContent);

RolesConfiguration memory accessManagerConfiguration = abi.decode(rawJson, (RolesConfiguration));

console.log("Access manager institution admin:", address(accessManagerConfiguration.admin));

// Calculate total number of calldatas needed
uint256 totalCalldatas = 14 + accessManagerConfiguration.customExternalCallers.length + 1; // +1 for revoke role
bytes[] memory calldatas = new bytes[](totalCalldatas);
uint256 calldataIndex = 0;

calldatas[calldataIndex++] = abi.encodeCall(AccessManager.labelRole, (DEPOSITOR_ROLE_ID, "Depositor"));
calldatas[calldataIndex++] = abi.encodeCall(AccessManager.labelRole, (WITHDRAWER_ROLE_ID, "Withdrawer"));
calldatas[calldataIndex++] =
abi.encodeCall(AccessManager.labelRole, (CUSTOM_EXTERNAL_CALLER_ROLE_ID, "Custom External Caller"));
calldatas[calldataIndex++] =
abi.encodeCall(AccessManager.labelRole, (WITHDRAWAL_MANAGER_ROLE_ID, "Withdrawal Manager"));
calldatas[calldataIndex++] = abi.encodeCall(AccessManager.labelRole, (ORACLE_ROLE_ID, "Oracle"));
// Grant the admin role to the institution admin, without any delay
calldatas[calldataIndex++] =
abi.encodeCall(AccessManager.grantRole, (ADMIN_ROLE_ID, accessManagerConfiguration.admin, 0));

bytes4[] memory depositorSelectors = new bytes4[](3);
depositorSelectors[0] = IInstitutionalVault.depositETH.selector;
depositorSelectors[1] = IInstitutionalVault.mint.selector;
depositorSelectors[2] = IInstitutionalVault.deposit.selector;

calldatas[calldataIndex++] = abi.encodeCall(
AccessManager.setTargetFunctionRole,
(accessManagerConfiguration.vault, depositorSelectors, DEPOSITOR_ROLE_ID)
);

bytes4[] memory withdrawerSelectors = new bytes4[](2);
withdrawerSelectors[0] = IInstitutionalVault.withdraw.selector;
withdrawerSelectors[1] = IInstitutionalVault.redeem.selector;

calldatas[calldataIndex++] = abi.encodeCall(
AccessManager.setTargetFunctionRole,
(accessManagerConfiguration.vault, withdrawerSelectors, WITHDRAWER_ROLE_ID)
);

bytes4[] memory withdrawalManagerSelectors = new bytes4[](2);
withdrawalManagerSelectors[0] = IInstitutionalVault.queueWithdrawals.selector;
withdrawalManagerSelectors[1] = IInstitutionalVault.completeQueuedWithdrawals.selector;

calldatas[calldataIndex++] = abi.encodeCall(
AccessManager.grantRole, (WITHDRAWAL_MANAGER_ROLE_ID, accessManagerConfiguration.withdrawalManager, 0)
);

calldatas[calldataIndex++] =
abi.encodeCall(AccessManager.grantRole, (ORACLE_ROLE_ID, accessManagerConfiguration.admin, 0));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oracle role to admin? also it is not assigned to any function. Will it be used externally?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be assigned to the setValidatorsETH but it's not part of the interface


calldatas[calldataIndex++] = abi.encodeCall(
AccessManager.setTargetFunctionRole,
(accessManagerConfiguration.vault, withdrawalManagerSelectors, WITHDRAWAL_MANAGER_ROLE_ID)
);

calldatas[calldataIndex++] =
abi.encodeCall(AccessManager.grantRole, (DEPOSITOR_ROLE_ID, accessManagerConfiguration.admin, 0));

calldatas[calldataIndex++] =
abi.encodeCall(AccessManager.grantRole, (WITHDRAWER_ROLE_ID, accessManagerConfiguration.admin, 0));

bytes4[] memory customExternalCallerSelectors = new bytes4[](1);
customExternalCallerSelectors[0] = IInstitutionalVault.customExternalCall.selector;

calldatas[calldataIndex++] = abi.encodeCall(
AccessManager.setTargetFunctionRole,
(accessManagerConfiguration.vault, customExternalCallerSelectors, CUSTOM_EXTERNAL_CALLER_ROLE_ID)
);

// Grant the custom external caller role to the custom external callers
for (uint256 i = 0; i < accessManagerConfiguration.customExternalCallers.length; i++) {
calldatas[calldataIndex++] = abi.encodeCall(
AccessManager.grantRole,
(CUSTOM_EXTERNAL_CALLER_ROLE_ID, accessManagerConfiguration.customExternalCallers[i], 0)
);
}

// Revoke the admin role from the puffer ops multisig - Clean up
calldatas[calldataIndex++] =
abi.encodeCall(AccessManager.revokeRole, (ADMIN_ROLE_ID, accessManagerConfiguration.pufferOpsMultisig));

bytes memory encodedMulticall = abi.encodeCall(Multicall.multicall, (calldatas));

console.log("Total calldatas:", totalCalldatas, "calldataIndex:", calldataIndex);
console.log("Encoded multicall:");
console.logBytes(encodedMulticall);
}
}
14 changes: 0 additions & 14 deletions src/Counter.sol

This file was deleted.

Loading