Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
86afa4b
Removed unused function
eladiosch Jul 3, 2025
202c7f1
Created PufferLogic contract and adapted existing ones (WIP)
eladiosch Jul 7, 2025
0b4a2b8
Adapted previous tests and improved signatures
eladiosch Jul 7, 2025
37fff25
Changed ProtocolLogic structure. Moved more logic to ext contract (WIP)
eladiosch Jul 7, 2025
27dea10
Fixed and simplify delegatecalls
eladiosch Jul 8, 2025
50536f7
Refactor delegatecalls and small fixes
eladiosch Jul 8, 2025
7b53076
Refactor PufferConstants to PufferProtocolBase and moved more logic t…
eladiosch Jul 8, 2025
ec3e5fe
forge fmt
eladiosch Jul 8, 2025
9d2251f
Removed flow to deposit VT with Permit
eladiosch Jul 10, 2025
c104f39
Added tests to increase coverage
eladiosch Jul 10, 2025
48c5b53
forge fmt
eladiosch Jul 10, 2025
4e44801
Refactored interfaces and adapted tests (protocol WIP)
eladiosch Jul 14, 2025
eab8cfc
Changed approach of the delegatecall to logic contract
eladiosch Jul 14, 2025
495ac9d
Removed selector constants
eladiosch Jul 15, 2025
bf0c713
Added some natspec to the fallback function
eladiosch Jul 15, 2025
a19d9a0
Moved logic from GuardianModule to Protocol to avoid re-deploying con…
eladiosch Jul 15, 2025
5501856
forge fmt
eladiosch Jul 15, 2025
f3dafab
Added basic checks to withdrawValidationTime and added missing natspec
eladiosch Jul 15, 2025
8d546b1
forge fmt
eladiosch Jul 15, 2025
522f503
Update mainnet-contracts/src/PufferProtocol.sol
eladiosch Jul 16, 2025
e7fb64e
Update mainnet-contracts/src/PufferProtocol.sol
eladiosch Jul 16, 2025
76a3233
Update mainnet-contracts/src/PufferProtocol.sol
eladiosch Jul 16, 2025
c90f5da
Update mainnet-contracts/src/PufferProtocol.sol
eladiosch Jul 16, 2025
e181e10
Update mainnet-contracts/src/PufferProtocolLogic.sol
eladiosch Jul 16, 2025
fad967d
Update mainnet-contracts/src/PufferProtocol.sol
eladiosch Jul 16, 2025
b982b2e
Using modifier (with require) to check deadlines
eladiosch Jul 16, 2025
3c16eb3
Changed reverts to require and refactored to avoid stack too deep
eladiosch Jul 16, 2025
3599a63
Added restricted for the Logic contract and improved natspec
eladiosch Jul 16, 2025
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
21 changes: 18 additions & 3 deletions mainnet-contracts/script/DeployPuffer.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { RewardsCoordinatorMock } from "../test/mocks/RewardsCoordinatorMock.sol
import { EigenAllocationManagerMock } from "../test/mocks/EigenAllocationManagerMock.sol";
import { RestakingOperatorController } from "../src/RestakingOperatorController.sol";
import { RestakingOperatorController } from "../src/RestakingOperatorController.sol";
import { PufferProtocolLogic } from "../src/PufferProtocolLogic.sol";
/**
* @title DeployPuffer
* @author Puffer Finance
Expand Down Expand Up @@ -181,8 +182,21 @@ contract DeployPuffer is BaseScript {
address(moduleManager), abi.encodeCall(moduleManager.initialize, (address(accessManager)))
);

PufferProtocolLogic pufferProtocolLogic = new PufferProtocolLogic({
pufferVault: PufferVaultV5(payable(pufferVault)),
validatorTicket: ValidatorTicket(address(validatorTicketProxy)),
guardianModule: GuardianModule(payable(guardiansDeployment.guardianModule)),
moduleManager: address(moduleManagerProxy),
oracle: IPufferOracleV2(oracle),
beaconDepositContract: getStakingContract(),
pufferRevenueDistributor: payable(revenueDepositor)
});

// Initialize the Pool
pufferProtocol.initialize({ accessManager: address(accessManager) });
pufferProtocol.initialize({
accessManager: address(accessManager),
pufferProtocolLogic: address(pufferProtocolLogic)
});

vm.label(address(accessManager), "AccessManager");
vm.label(address(operationsCoordinator), "OperationsCoordinator");
Expand Down Expand Up @@ -216,8 +230,9 @@ contract DeployPuffer is BaseScript {
pufferVault: address(0), // overwritten in DeployEverything
pufferDepositor: address(0), // overwritten in DeployEverything
weth: address(0), // overwritten in DeployEverything
revenueDepositor: address(0) // overwritten in DeployEverything
});
revenueDepositor: address(0), // overwritten in DeployEverything
pufferProtocolLogic: address(pufferProtocolLogic)
});
}

function getStakingContract() internal returns (address) {
Expand Down
1 change: 1 addition & 0 deletions mainnet-contracts/script/DeploymentStructs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct PufferProtocolDeployment {
address weth; // from pufETH repository (dependency)
address timelock; // from pufETH repository (dependency)
address revenueDepositor;
address pufferProtocolLogic;
}

struct BridgingDeployment {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "forge-std/Script.sol";
import { stdJson } from "forge-std/StdJson.sol";
import { Permit } from "../src/structs/Permit.sol";
import { ValidatorKeyData } from "../src/struct/ValidatorKeyData.sol";
import { IPufferProtocol } from "../src/interface/IPufferProtocol.sol";
import { IPufferProtocolFull } from "../src/interface/IPufferProtocolFull.sol";
import { PufferProtocol } from "../src/PufferProtocol.sol";
import { PufferVaultV5 } from "../src/PufferVaultV5.sol";
import { ValidatorTicket } from "../src/ValidatorTicket.sol";
Expand Down Expand Up @@ -107,7 +107,7 @@ contract GenerateBLSKeysAndRegisterValidators is Script {
numBatches: 1
});

IPufferProtocol(protocolAddress).registerValidatorKey(
IPufferProtocolFull(protocolAddress).registerValidatorKey(
validatorData, moduleName, 0, new bytes[](0), block.timestamp + SIGNATURE_VALIDITY_PERIOD
);

Expand Down Expand Up @@ -156,8 +156,9 @@ contract GenerateBLSKeysAndRegisterValidators is Script {
function _generateValidatorKey(uint256 idx, bytes32 moduleName) internal {
uint256 numberOfGuardians = pufferProtocol.GUARDIAN_MODULE().getGuardians().length;
bytes[] memory guardianPubKeys = pufferProtocol.GUARDIAN_MODULE().getGuardiansEnclavePubkeys();
address moduleAddress = IPufferProtocol(protocolAddress).getModuleAddress(moduleName);
bytes memory withdrawalCredentials = IPufferProtocol(protocolAddress).getWithdrawalCredentials(moduleAddress);
address moduleAddress = IPufferProtocolFull(protocolAddress).getModuleAddress(moduleName);
bytes memory withdrawalCredentials =
IPufferProtocolFull(protocolAddress).getWithdrawalCredentials(moduleAddress);

string[] memory inputs = new string[](17);
inputs[0] = "coral-cli";
Expand Down
11 changes: 6 additions & 5 deletions mainnet-contracts/script/SetupAccess.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { GenerateAccessManagerCallData } from "../script/GenerateAccessManagerCa
import { GenerateAccessManagerCalldata2 } from "../script/AccessManagerMigrations/GenerateAccessManagerCalldata2.s.sol";
import { GenerateRestakingOperatorCalldata } from
"../script/AccessManagerMigrations/07_GenerateRestakingOperatorCalldata.s.sol";
import { IPufferProtocolLogic } from "../src/interface/IPufferProtocolLogic.sol";

import {
ROLE_ID_OPERATIONS_MULTISIG,
Expand Down Expand Up @@ -322,8 +323,8 @@ contract SetupAccess is BaseScript {

bytes4[] memory paymasterSelectors = new bytes4[](3);
paymasterSelectors[0] = PufferProtocol.provisionNode.selector;
paymasterSelectors[1] = PufferProtocol.skipProvisioning.selector;
paymasterSelectors[2] = PufferProtocol.batchHandleWithdrawals.selector;
paymasterSelectors[1] = IPufferProtocolLogic.skipProvisioning.selector;
paymasterSelectors[2] = IPufferProtocolLogic.batchHandleWithdrawals.selector;

calldatas[1] = abi.encodeWithSelector(
AccessManager.setTargetFunctionRole.selector,
Expand All @@ -333,12 +334,12 @@ contract SetupAccess is BaseScript {
);

bytes4[] memory publicSelectors = new bytes4[](6);
publicSelectors[0] = PufferProtocol.registerValidatorKey.selector;
publicSelectors[0] = IPufferProtocolLogic.registerValidatorKey.selector;
publicSelectors[1] = PufferProtocol.depositValidatorTickets.selector;
publicSelectors[2] = PufferProtocol.withdrawValidatorTickets.selector;
publicSelectors[3] = PufferProtocol.revertIfPaused.selector;
publicSelectors[4] = PufferProtocol.depositValidationTime.selector;
publicSelectors[5] = PufferProtocol.withdrawValidationTime.selector;
publicSelectors[4] = IPufferProtocolLogic.depositValidationTime.selector;
publicSelectors[5] = IPufferProtocolLogic.withdrawValidationTime.selector;

calldatas[2] = abi.encodeWithSelector(
AccessManager.setTargetFunctionRole.selector,
Expand Down
35 changes: 27 additions & 8 deletions mainnet-contracts/src/GuardianModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,22 @@
/**
* @inheritdoc IGuardianModule
*/
function validateWithdrawalRequest(bytes[] calldata eoaSignatures, bytes32 messageHash) external view {
function validateWithdrawalRequest(

Check warning on line 220 in mainnet-contracts/src/GuardianModule.sol

View check run for this annotation

Codecov / codecov/patch

mainnet-contracts/src/GuardianModule.sol#L220

Added line #L220 was not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

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

This would require us to deploy a new GuardianModule, we could have this message logic in the protocol, and use

GUARDIAN_MODULE.validateGuardiansEOASignatures

That way, we wouldn't need to re-audit/redeploy

GuardianModule

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to re-deploy the GuardianModule anyways since the struct StoppedValidatorsInfo has changes. It was commented in the Pectra PR => #115 (comment)

Copy link
Collaborator

Choose a reason for hiding this comment

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

If we move that signature logic to the protocol, we might not need to, please check my big comment on the PR

address node,
bytes memory pubKey,
uint256 gweiAmount,
uint256 nonce,
uint256 deadline,
bytes[] calldata guardianEOASignatures
) external view {
// Recreate the message hash
bytes32 signedMessageHash = LibGuardianMessages._getAnyHashedMessage(messageHash);
bytes32 signedMessageHash =
LibGuardianMessages._getWithdrawalRequestMessage(node, pubKey, gweiAmount, nonce, deadline);

Check warning on line 230 in mainnet-contracts/src/GuardianModule.sol

View check run for this annotation

Codecov / codecov/patch

mainnet-contracts/src/GuardianModule.sol#L229-L230

Added lines #L229 - L230 were not covered by tests

bool validSignatures =
validateGuardiansEOASignatures({ eoaSignatures: eoaSignatures, signedMessageHash: signedMessageHash });
bool validSignatures = validateGuardiansEOASignatures({

Check warning on line 232 in mainnet-contracts/src/GuardianModule.sol

View check run for this annotation

Codecov / codecov/patch

mainnet-contracts/src/GuardianModule.sol#L232

Added line #L232 was not covered by tests
eoaSignatures: guardianEOASignatures,
signedMessageHash: signedMessageHash
});

if (!validSignatures) {
revert Unauthorized();
Expand All @@ -232,12 +242,21 @@
/**
* @inheritdoc IGuardianModule
*/
function validateTotalEpochsValidated(bytes[] calldata eoaSignatures, bytes32 messageHash) external view {
function validateTotalEpochsValidated(
address node,
uint256 totalEpochsValidated,
uint256 nonce,
uint256 deadline,
bytes[] calldata guardianEOASignatures
) external view {
// Recreate the message hash
bytes32 signedMessageHash = LibGuardianMessages._getAnyHashedMessage(messageHash);
bytes32 signedMessageHash =
LibGuardianMessages._getTotalEpochsValidatedMessage(node, totalEpochsValidated, nonce, deadline);

bool validSignatures =
validateGuardiansEOASignatures({ eoaSignatures: eoaSignatures, signedMessageHash: signedMessageHash });
bool validSignatures = validateGuardiansEOASignatures({
eoaSignatures: guardianEOASignatures,
signedMessageHash: signedMessageHash
});

if (!validSignatures) {
revert Unauthorized();
Expand Down
35 changes: 31 additions & 4 deletions mainnet-contracts/src/LibGuardianMessages.sol
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,39 @@
}

/**
* @notice Returns the message to be signed for any message
* @param hashedMessage is the hashed message to be signed
* @notice Returns the message to be signed for the total epochs validated
* @param node is the node operator address
* @param totalEpochsValidated is the total epochs validated
* @param nonce is the nonce for the node and the function selector
* @param deadline is the deadline of the signature
* @return the message to be signed
*/
function _getAnyHashedMessage(bytes32 hashedMessage) internal pure returns (bytes32) {
return hashedMessage.toEthSignedMessageHash();
function _getTotalEpochsValidatedMessage(
address node,
uint256 totalEpochsValidated,
uint256 nonce,
uint256 deadline
) internal pure returns (bytes32) {
return keccak256(abi.encode(node, totalEpochsValidated, nonce, deadline)).toEthSignedMessageHash();
}

/**
* @notice Returns the message to be signed for the withdrawal request
* @param node is the node operator address
* @param pubKey is the public key
* @param gweiAmount is the amount in gwei
* @param nonce is the nonce for the node and the function selector
* @param deadline is the deadline of the signature
* @return the message to be signed
*/
function _getWithdrawalRequestMessage(

Check warning on line 116 in mainnet-contracts/src/LibGuardianMessages.sol

View check run for this annotation

Codecov / codecov/patch

mainnet-contracts/src/LibGuardianMessages.sol#L116

Added line #L116 was not covered by tests
address node,
bytes memory pubKey,
uint256 gweiAmount,
uint256 nonce,
uint256 deadline
) internal pure returns (bytes32) {
return keccak256(abi.encode(node, pubKey, gweiAmount, nonce, deadline)).toEthSignedMessageHash();

Check warning on line 123 in mainnet-contracts/src/LibGuardianMessages.sol

View check run for this annotation

Codecov / codecov/patch

mainnet-contracts/src/LibGuardianMessages.sol#L123

Added line #L123 was not covered by tests
}
}
/* solhint-disable func-named-parameters */
19 changes: 0 additions & 19 deletions mainnet-contracts/src/ProtocolSignatureNonces.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,23 +78,4 @@ abstract contract ProtocolSignatureNonces {
return $._nonces[selector][owner]++;
}
}

/**
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
* @param selector The function selector that determines the nonce space
* @param owner The address whose nonce to validate and consume
* @param nonce The expected nonce value
*
* @dev This function validates that the provided nonce matches the expected
* current nonce before consuming it. This prevents replay attacks and
* ensures proper signature ordering.
*
* @dev Reverts with InvalidAccountNonce if the nonce doesn't match.
*/
function _useCheckedNonce(bytes32 selector, address owner, uint256 nonce) internal virtual {
uint256 current = _useNonce(selector, owner);
if (nonce != current) {
revert InvalidAccountNonce(selector, owner, current);
}
}
}
Loading
Loading