Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
16 changes: 15 additions & 1 deletion 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
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 @@ contract GuardianModule is AccessManaged, IGuardianModule {
/**
* @inheritdoc IGuardianModule
*/
function validateWithdrawalRequest(bytes[] calldata eoaSignatures, bytes32 messageHash) external view {
function validateWithdrawalRequest(
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);

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

if (!validSignatures) {
revert Unauthorized();
Expand All @@ -232,12 +242,21 @@ contract GuardianModule is AccessManaged, IGuardianModule {
/**
* @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 @@ library LibGuardianMessages {
}

/**
* @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(
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();
}
}
/* 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